java学习笔记多线程学习总结(下)
来源:互联网 发布:java中求最大公约数 编辑:程序博客网 时间:2024/05/22 00:27
八、线程间的通信
线程间通信其实就是多个线程在操作同一个资源,但是操作的动作不同。
线程间通信例子:
eg:一个存一个输出。两个不同操作一个共享数据,形象显示线程间的通信。
class Res // 定义资源类
{ String name; String sex; }
class Input implements Runnable // 定义一个线程用于输入
{
private Res r;
Input(Res r){ this.r = r; }
public void run() // 线程执行语句覆写run,用于存入
{
int x=0;
while(true)
{
Synchronized(r)/(Input.class)/(output.class) // 线程同步
{
if(x==0)
{ r.name=”mike”; r.sex=”man”; }
else
{ r.name=”丽丽”; r.sex=”女女女女”; }
x=(x+1)%2;
}
}
}
}
class output implements Runnable // 定义一个线程类实现Runnable接口用于输出
{
private Res r;
output(Res r){ this.r=r; }
public void run() // 线程执行语句覆写run,用于输入
{
while(true)
{
Synchronized(r) // 线程同步前提多线程,一个锁
{ System.out.println(r.name+”…”+r.sex); }
}
}
}
class InputOutputDemo // 主函数
{
public static void main(String[] args)
{
Res r = new Res(); // 实例一个共享资源传参给2个线程执行。
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in); // 实例化两个线程
Thread t2 = new Thread(out);
t1.start(); // 启动两个线程
t2.start();
}
}
wait()、notify()、notifyAll()必须用在同步中(因为要锁)并用锁对象调用方法。此三种方法定义在Object类中,为了使任意对象都可以调用。注意到实现一进一出的情况,故引入wait()和notify()方法。
wait()方式继承在Object,需要抛出异常。sleep方法是Thread类都抛出异常interrupt异常。
notify()方法用于唤醒全部线程(等待中的)
说明:wait、notify、notifyAll都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用同步中,因为只 有同步才具有锁。
为什么这些操作线程的方法要定义Object类中呢?
这是因为这些方法在操作同步中线程时,都必须要标识他们所操作的线程持有的锁,又有同一个锁上的被等待线程,可以被同一个锁上notify唤醒,不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。存入取出程序的简化示例:
class Res
{
private String name;
private String sex;
private Boolean flag = false;
public Synchronized void set(String name,String sex)
{
if(flag)
try{ this.wait(); }catch(Exception e){ }
this.name = name;
this.sex =sex;
flag = true;
this.notify();
}
public Synchronized void out()
{ System.out.println(name+”,,,”+sex); }
}
class Input implements Runnable
{
private Res r;
Input(Res r)
{ this.r = r; }
public void run()
{
int x=0;
while(true)
{
if(x==0)
r.set(“mike”,”man”);
else
r.set(“丽丽”,”女女女女”);
r=(x+1)%2;
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r){ this.r=r; }
public void run()
{
while(true)
{
r.out();
}
}
}
class InputOutputDemo2
{
public static void main(String[] args)
{
Resr = new Res();
newThread(new Input(r)).start();
newThread(new Output(r)).start();
}
}
三、线程等待
当多个线程操作同一数据时,线程需要等待执行。
线程等待示例程序:
线程间通信——生产者消费者
class Resource
{
privateString name;
privateint count=1;
privateboolean flag = false;
publicsynchronized void set(String name)
{
if(flag)
try{this.wait();}catch(Exceptione){}
this.name=name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"......生产者。。。"+this.name);
flag=true;
this.notify();
}
publicsynchronized void out()
{
if(!flag)
try{wait();}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()+"...消费者。。。"+this.name);
flag=false;
this.notify();
}
}
class Producer implements Runnable
{
privateResource res;
Producer(Resourceres)
{
this.res=res;
}
publicvoid run()
{
while(true)
{
res.set("+商品+");
}
}
}
class Consumer implements Runnable
{
privateResource res;
Consumer(Resourceres)
{
this.res=res;
}
publicvoid run()
{
while(true)
{
res.set("+商品+");
}
}
}
public class ProducerConsumerDemo {
publicstatic void main(String[] args) {
//TODO 自动生成的方法存根
Resourcer = new Resource();
Producerp = new Producer(r);
Consumerc = new Consumer(r);
Threadt1 = new Thread(p);
Threadt2 = new Thread(c);
Threadt3 = new Thread(p);
Threadt4 = new Thread(c);
t3.start();
t4.start();
t1.start();
t2.start();
}
}
多加几个线程后即多几个生产者和消费者后:发现出现生产两次,消费一次。或生产一次消费两次的情况。产生这种情况的原因是唤醒后没有判断标记。将if(flag)改为while(flag)。但这样会产生全部等待的情况,又不同于死锁。此时将notify改为notifyAll唤醒。if(flag)和notify只应用于,生产者和消费者都是一个的情况。
四、Java1.5新特性,Lock对象及Condition
JDK1.5中提供了多线程升级解决方案。将同步Synchronized替换成现实Lock操作。将Object中的wait,notify,notifyAll,替换了Condition对象。该对象可以通过Lock锁进行获取。该示例中实现了本方只唤醒对方的操作。一个锁可以对应对个condition,之前一个锁只对应一组wait..notify。且,释放锁的动作在finally中,一定会执行。
Condition将Object监视器方法(wait、notify、notifyAll)分解成截然不同的对象,以便通过这些对象与任意Lock实现组合使用,为每个对象提供多个等待set(wait-set )。其中,Lock替代了synchronized方法和语句的使用,Condition替代了Object监视器方法的使用(wait、notify、notifyAll)。
线程间通信——生产者消费者2(使用新特性替换synchronized)
import java.util.concurrent.locks.*;
class Resource
{
privateString name;
privateint count=1;
privateboolean flag = false;
privateLock lock = new ReentrantLock(); // 定义Lock
privateCondition condition_pro = lock.newCondition(); // 通过Lock定义Condition
privateCondition condition_con = lock.newCondition(); // 通过Lock定义Condition
publicvoid set(String name)throws InterruptedException await方法会抛出异常
{
lock.lock(); // 锁
try
{
while(flag)
condition_pro.await(); // 调用await方法等待。
this.name=name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"......生产者。。。"+this.name);
flag=true;
condition_con.signalAll(); // 唤醒线程
}
finally
{
lock.unlock(); // 解锁,必须执行,释放资源
}
}
publicvoid out()throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"...消费者。。。"+this.name);
flag=false;
condition_pro.signalAll();
}
finally
{
lock.unlock();
}
}
}
class Producer implements Runnable
{
privateResource res;
Producer(Resourceres)
{
this.res=res;
}
publicvoid run()
{
while(true)
{
try{
res.set("+商品+");
}catch (InterruptedException e) {
//TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable
{
privateResource res;
Consumer(Resourceres)
{
this.res=res;
}
publicvoid run()
{
while(true)
{
try{
res.out();
}catch (InterruptedException e) {
//TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
public classProducerConsumerDemoLockCondition {
publicstatic void main(String[] args) {
//TODO 自动生成的方法存根
Resourcer = new Resource();
Producerp = new Producer(r);
Consumerc = new Consumer(r);
Threadt1 = new Thread(p);
Threadt2 = new Thread(c);
Threadt3 = new Thread(p);
Threadt4 = new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
五、线程的停止
1、定义循环结束标记
因为线程运行代码一般都是循环,只要控制了循环即可。
2、使用interrupt(中断)
该方法是结束线程的冻结状态,使线程回到运行状态中来。
(不用stop方法是因为他有bug,强制停止。)
(suspend方法会发生死锁,也停用)stop方法已经过时如何停止线程? 只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束。也就是线程结束。
停止循环的一种特殊情况:
当线程处于冻结状态,就不会读取到标记,那么线程就不会结束.当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结状态进行清除.强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束.Thread类中提供了该方法,interrupted方法,清除线程的冻结状态class StopThread implements Runnable //定义一个线程类
{
private boolean flag = true;
public synchronized void run() //线程执行的语句
{
while(flag)
{
try
{
wait();//为真时等待
}
catch(InterruptedExceptione)
{
System.out.println(Thread.currentThread().getName()+"....Exception");
flag= false; //出现异常说明强制中止,改变标记使结束.
}
System.out.println(Thread.currentThread().getName()+"....run"); //为假时执行
}
}
publicvoid changeFlag() // 定义改变标记方法
{
flag= false;
}
}
class StopThreadDemo
{
publicstatic void main(String[] args) //主函
{
StopThreadst = new StopThread(); //实例一个实现Runnable接口的线程类
Threadt1 = new Thread(st);
Threadt1 = new Thread(st); //定义两个Thread类对像
t1.start();
t2.start();
intnum = 0;
while(true) // 主线程执行语句
{
if(num++== 60)
{
//st.changeFlag();
t1.interrupt(); // num等于60时中止线程
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+".......num"); //主线程输出
}
System.out.println("over");
}
}
class StopThreadimplements Runnable //定义一个线程类
{
private boolean flag = true;
public void run() //线程执行的语句
{
while(flag)
{
System.out.println(Thread.currentThread().getName()+"....run"); //为假时执行
}
}
public void changeFlag() // 定义改变标记方法
{
flag = false;
}
}
classStopThreadDemo
{
public static void main(String[]args) //主函
{
StopThread st = newStopThread(); //实例一个实现Runnable接口的线程类
Thread t1 = new Thread(st);
Thread t1 = newThread(st); //定义两个Thread类对像
t1.setDaemon(true);
t2.setDaemon(true); //设置t1,t2为守护线程主线程结束后,他们自动结束。
t1.start();
t2.start();
int num = 0;
while(true) // 主线程执行语句
{
if(num++ == 60)
{
break;
}
System.out.println(Thread.currentThread().getName()+".......num"); //主线程输出
}
System.out.println("over");
}
}
七、Join方法抢夺CPU的执行权
Join:当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完A才会执行。
Join可以用来临时加入线程执行。Join:当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完A才会执行。
Join可以用来临时加入线程执行。
class Demo imlements Runnable
{
publicvoid run() // 线程的执行内容
{
for(int x=0;x<70;x++)
{
System.out.println(Thread.currentThread().getName()+”…..”+x);
}
}
}
class JoinDemo
{
publicstatic void main(String[] args) // 主函
{
Demod = new Demo();
Threadt1 = new Thread(d); // 两个线程
Threadt2 = new Thread(d);
t1.start();
t1.join(); // 抢夺CPU的执行权,主线程停止等待t1执行完成后主线程恢复。
t2.start();
for(intx=0;x<80;x++) // 主线程执行内容
{
System.out.println(“main…..”+x);
}
System.out.println(“over”);
}
}
八、线程中的ToString()方法
ToString()方法:返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
线程组:
谁开启的就属于哪个组,例如main。线程组是一个类可以自定义组ThreadGroup类。
线程优先级
线程优先级代表着抢资源的频率。注所有的线程包括主线程默认优先级是5。
更改线程的优先级:
setPriority(int newPriority)方法。参数:(MAX/MIN/NORM_PRIORITY)
eg: setPriority(Thread. MAX _PRIORITY) 设置为最大优先级
九、yield方法
yield方法为静态方法。用Thread调用。暂停当前正在执行的线程对象,并执行其它线程。强制临时释放执行权,减缓线程运行,可以达到线程都有机会平均运行效果。
十、开发中创建线程
什么时候用到多线程?
当某些代码需要同时被执行时,就用单独的线程进行封装。
- java学习笔记多线程学习总结(下)
- java学习笔记多线程学习总结(上)
- java中多线程学习笔记总结
- Java多线程学习(总结)
- Java学习笔记(多线程)
- Java多线程(学习笔记)
- Java多线程(全)学习笔记(下)
- java多线程学习总结
- java多线程学习总结
- Java多线程学习总结
- java多线程学习总结
- java 多线程学习总结
- java多线程学习总结
- Java学习总结--多线程
- java多线程学习总结
- java多线程-学习总结
- Java多线程学习总结
- Java多线程学习总结
- Linux下守护进程(daemon)和管道的结合使用(代码保留)
- 重造轮子-random5到random7
- [Android]仿即时通信App界面的实现
- Linux环境使用xampp搭建DVWA渗透测试平台
- 欢迎使用CSDN-markdown编辑器
- java学习笔记多线程学习总结(下)
- Java线程进入
- message_flood
- 下拉刷新效果
- 常见的HTTP状态码
- iOS App键盘第一次启动延迟问题
- POJ 3243 Clever Y (求X^Y mod Z = K)
- js判断是否定义
- leetcode之Add Digits