java多线程的同步 通信以及生产消费者问题
Demo1
/* Runable接口比直接从Thread继承方便的多 。
* new Thread(...) ;这样即使我们传递了同一个实现了Runnable接口的多个对象那么 也是多个线程 ,而且多个线程共享数据域.
* 否则new Thread 创建的多个线程之间 互不相干 ,数据之间互不干涉
* 同步就是为了实现 在多个线程同时对一个资源进行操作的时候 要一个一个的执行 ,
* 只有等占有CPU的 线程完事之后 其他等待线程才能进入就绪状态等待运行
* java中可以用 synchrozined(Object obj){} 实现代码块的同步 参数是任意对象
* 不但可以利用synchronized语句块 也可以在方法的前面 声明 synchronized
* 同步原理是对象的标志位 初始为1 当进入代码块后 obj的标志位变为 0 这时候其他线程则不能 进入代码块执行 而进入等待状态
* 直到先进入的那个线程完事然后就会为这个线程解锁 。 其他线程才可能开始运行 火车票的售票系统就是一个多线程很好的运用的例子
* 同步是以程序的性能为代价的 ,同步方法是以类的this对象为同步对象的 而 synchronized块是以我们指定的对象为 同步对象
* 如果想让代码块和同步方法同步那么 使用的同步对象 必须都为this
*/
public class ThreadDemo2
{
public static void main(String []args)
{
MyThread mt=new MyThread() ;
//mt.start() ;
new Thread(mt) .start() ;
try
{
Thread.sleep(10) ; //每当产生一个线程CPU不会立马去执行 ,这之间既有一个微小的时间间隔 。
}
catch(Exception e)
{
System.out.println(e.toString()) ;
}
mt.str="method";
new Thread(mt) .start() ;
}
}
class MyThread implements Runnable// extends Thread
{
int tickets=100 ;
String str=new String("");
public void run()
{
if(str.equals("method"))
{
while(true)
{
running() ;
}
}
else
{
while(true)
{
synchronized(str)
{
if(tickets>0 )
{
System.out.println("block:"+Thread.currentThread().getName()+"sells"+tickets--);
}
}
}
}
}
public synchronized void running()
{
if(tickets>0)
{
try{Thread.sleep(10);}catch(Exception ex){}
System.out.print("method:") ;
System.out.println(Thread.currentThread() +"sell " + tickets-- ) ;
}
}
}
Demo2:
/*
* java多线程中 有前台线程和后台线程,前台线程 是指 main所在的主线程 和其他 创建的线程 ,如果在线程调用start 之前调用 setDeamon(true)
* 那么 这个线程就是一个后台线程,在进程中如果没有一个前台线程 那么后台线程也随之退出,从而进程也退出 。如果没有调用setDeamon(true)或者
* 调用setDeamom(false)那么这个线程就是前台线程 ,只要一个进程中还存在前台线程 那么即使mian方法所在的线程退出了 ,那么这个前台子线程也会继续执行
* 直至退出 。
* Tread类额join方法 是将一个线程合并到另一个线程中, 可以设置合并的时间间隔
* 我们实现自己的线程类有2中方法 :
* 1、直接从Thread继承而来 实现 run方法 。
* 2、实现Runnable接口,并且实现run方法 。 Thread th=new Thread(....) ;//吧我们自己实现的类的对象作为参数传进去 .
* join 方法可以将一个线程合并到另一个线程 中 而且还可以指定线程合并的时间间隔
*
*/
public class ThreadDemo1
{
public static void main(String[]args)
{
//MyThread tt=new MyThread() ; tt.start() ;可以从 Thread类派生一个线程类
Thread tt=new Thread(new MyThread()) ; //可以通过Thread类的带参数的构造方法 传递一个实现了Runnable接口的对象
// tt.setDaemon(true) ;//将线程设置为 后台线程 主线层退出这个线程也会随着退出
tt.start() ;
int index=0 ;
while(true)
{
if(index++==100)
try{
tt.join(5000) ;
}
catch(Exception ex)
{
System.out.println(ex.toString()) ;
}
System.out.println("run:"+Thread.currentThread().getName()) ;
}
}
}
class MyThread implements Runnable//extends Thread
{
public void run()
{
while(true)
{
System.out.println("run:"+Thread.currentThread().getName()) ;
}
}
}
Demo3:
/* 线程之间的通信是协调线程同步的重要方法 、
* Object类的 wait方法通告同步对象进入等待状态,直到其他线程得到同步对象 并且调用 notity方法 ,等待线程才会继续执行
* notify方法 是通告同步对象的等待线程进入恢复运行
* notifyAll通告所有堵塞线程恢复运行
* 下面是一个生产消费者的问题 ,在对于类的操作的时候 一定要有面向对象的思想 。 否则 就会非常的杂乱
*/
class Producer implements Runnable
{
Q q ;
public Producer(Q q)
{
this.q=q ;
}
public void run()
{
int i=0 ;
while(true)
{
/* synchronized(q)
{
if(q.bFull==true)
try{q.wait() ;}catch(Exception ex){}
if(i==0)
{
q.name="zhangsan" ;
try{
Thread.sleep(1) ;
}catch(Exception ex){}
q.sex="male" ;
}
else
{
q.name="lisi" ;
q.sex="female" ;
}
q.bFull=true ;
q.notify() ;
}
i=(i+1)%2 ;
*/
if(i==0 )
q.push("zhangsan","male");
else
q.push("lisi","female") ;
i=(i+1)%2 ;
}
}
}
class Consumer implements Runnable
{
Q q ;
public Consumer(Q q)
{
this.q=q ;
}
public void run()
{
while(true)
{
/* synchronized(q)
{
if(!q.bFull)
{
try{q.wait() ;}catch(Exception ex){}
}
System.out.println(q.name+":"+q.sex) ;
q.bFull=false ;
q.notify() ;
}
*/
q.get() ;
}
}
}
class Q //以面向对象的思想对线程之间的通信进行封装从而实现消费者 生产社的问题
{
String name="unknown" ;
String sex ="unknown" ;
boolean bFull=false ;
public synchronized void push(String name,String sex)
{
if(this.bFull==true)
try{wait() ;}catch(Exception ex){}
this.name=name ;
this.sex=sex ;
bFull=true ;
try{notify() ;}catch(Exception ex){}
}
public synchronized void get()
{
if(this.bFull==false)
try{wait() ;}catch(Exception ex){}
System.out.println("name:"+this.name+" sex:"+this.sex) ;
bFull=false ;
try{notify() ;}catch(Exception ex){}
}
}
class ThreadTest implements Runnable //这个线程类 来模拟线程的声明结束 因为Thread类的 stop suspend等方法都已经过时了
{ //所以有时候我们对于线程的开始和结束要自己设置标志位来
boolean bRun=true ;
int index=0 ;
public void stopMe()
{
bRun=false ;
}
public void run()
{
while(bRun)
{
if(++index>100)
stopMe() ;
System.out.println(Thread.currentThread().getName()+" is running!");
}
}
}
public class ThreadDemo3
{
public static void main(String[]args)
{
Q q=new Q() ;
new Thread(new Producer(q)).start() ;
new Thread(new Consumer(q)).start() ;
}
}