1、线程间通讯
就是多个线程在操作同一个资源,但是操作的动作不同。
多线程同步时千万注意同步前提:
使用同步原则一、线程:必须要有两个或者以上的线程; 使用同步原则二、锁:必须是多个线程使用同一个锁。
使用同步原则三、独:必须保证同步中只能有一个线程在运行。
class Resource{
String name;
String sex;
}
class Input implements Runnable{
private Resource r;
Input(Resource r){
this.r = r;
}
public void run(){
int x= 0;
while(true){
synchronized(r){//使用同步原则二、锁为同一个锁
if(x==0){
r.name = "lili";
r.sex = "girl";
} else{
r.name = "龟龟";
r.sex = "男";
}
x = (x+1)%2;
}
}
}
}
class Output implements Runnable{
private Resource r;
Output(Resource r){
this.r = r;
}
public void run(){
while(true){
synchronized(r){//使用同步原则二、锁为同一个锁
System.out.println(r.name+"******"+r.sex);
}
}
}
}
class InputOutputDemo03{
public static void main(String[] args){
Resource r = new Resource();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
2、等待唤醒机制
wait()、notify()、notifyAll()
第一、这些方法都用在同步中原因:用在都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中。
第二、这些方法都定义在Object类中原因:因为这些方法操作同步中线程时,都必须要标识他们所操作线程持有的锁,只有同一个锁上的被等待线程wait,可以被同一个锁上notify唤醒。不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象 ,所以可以被任意对象调用的方法定义在Object类中。
class Resource{
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(){
if(!flag){
try{this.wait();}catch(Exception e) {}
}
System.out.println(name+"****"+sex);
flag = false;
this.notify();
}
}
class Input implements Runnable{
private Resource r;
Input(Resource r){
this.r = r;
}
public void run(){
int x= 0;
while(true){
synchronized(r){//使用同步原则二、锁为同一个锁
if(x==0){
r.set("lili","girl");
} else{
r.set("龟龟","男");
}
x = (x+1)%2;
}
}
}
}
class Output implements Runnable{
private Resource r;
Output(Resource r){
this.r = r;
}
public void run(){
while(true){
r.out();
}
}
}
class InputOutputDemo03{
public static void main(String[] args){
Resource r = new Resource();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
/*Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start(); */
}
}
3、线程间通信---生产者消费者JDK5.0升级版
JDK1.5中提供了多线程升级解决方案:
将同步Synchronized替换成Lock操作;======》方便知道是什么时候锁、什么时候解锁
将Object中的wait\notify\notifyAll替换成Condition对象;======》可以唤醒对方锁对象
import java.util.concurrent.locks.*;
public class ProducerComsumerDemo02{
public static void main(String[] args){
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource{
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
public void set(String name) throws InterruptedException{
lock.lock();
try{
while(flag){
condition_pro.await();
}
this.name = name+"***"+count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
flag = true;
condition_con.signal();
}finally{
lock.unlock();
}
}
public void out() throws InterruptedException{
lock.lock();
try{
while(!flag){
condition_con.await();
System.out.println(Thread.currentThread().getName()+"****消费者****"+this.name);
flag = false;
condition_pro.signal();
}
}finally{
lock.unlock();
}
}
}
class Producer implements Runnable{
private Resource res;
Producer(Resource res){
this.res = res;
}
public void run(){
while(true){
try{
res.set("+商品+");
} catch(InterruptedException e){}
}
}
}
class Consumer implements Runnable{
private Resource res;
Consumer(Resource res){
this.res = res;
}
public void run(){
while(true){
try{
res.out();
} catch(InterruptedException e){}
}
}
}
4、停止线程
停止线程,stop方法已经过时。这时如何停止线程?只有一种方法,就是run方法结束。
开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:当线程处于冻结状态,就不会读取标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。Thread类提供方法interrupt()。
class StopThread implements Runnable{
private boolean flag = true;
public synchronized void run(){
while(flag){
try{
wait();
} catch(InterruptedException e){
System.out.println(Thread.currentThread().getName()+"...Exception");
flag = false;
}
System.out.println(Thread.currentThread().getName()+"......run");
}
}
public void changeFlag(){
flag = false;
}
}
public class StopThreadDemo{
public static void main(String[] args){
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 0;
while(true){
if(num++ == 60){
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+";;;;"+num);
}
System.out.println("over");
}
}
5、守护线程
public final void setDaemon(boolean on)
将该线程标记为守护线程或者用户线程,当正在运行的线程都是守护线程时,java虚拟机退出。
6、join方法
当A线程执行到了B线程.jion()方法时,A就会等待。等B线程都执行完,A才会执行。jion可以用来临时加入线程执行。
总结:
线程通讯