线程间的通信:
实际上就是多个线程在操作同一个资源,只是操作的动作不同。
等待唤醒机制:
wait();notify();notifyAll();
都要在同步中使用,因为要对持有监视器的线程操作。
所以要用在同步中,因为只有同步才具有监视器。
为什么这些操作线程的方法要定义在Object类中呢?
因为这些方法在操作同步中线程时,都必须要标识他们所操作线程的锁。
只有同一个锁上的wait等待线程,可以被同一个锁上notify唤醒
不可以对不同锁中的线程进行唤醒操作。
即等待和唤醒操作必须针对同一个监视器(锁)。
而监视器可以是任意对象,所以可以被任意对象调用的方法就定义在Object类中。
package com.itheima.test9;
class Res
{
private String name;
private String sex;
private boolean flag=false;
public synchronized void setRes(Stringname,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 Res r;
Input(Res r){
this.r = r;
}
public void run(){
int x = 0;
while (true)
{
if (x == 0){
r.setRes("mike", "man");
}else{
r.setRes("丽丽", "女女女女女女"); }
x = (x+1)%2;
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r){
this.r = r;
}
public void run(){
while (true)
{
r.out();
}
}
}
class InputOutputDemo
{
public static void main(String[] args)
{
Res r = new Res();
new Thread( new Input(r)).start();
new Thread(new Output(r)).start();
}
}
--------------------------------------------------------------------------------------------------
生产者消费者问题(Producer-Customer)
为什么要使用while和notifyAll?
1.当被唤醒的线程回复执行资格,需要再次判断,所以使用while循环。
2.因为需要唤醒对方线程,只用notify,容易出现只唤醒本方线程的情况某导致程序中所有线程等待。
JDK1.5以后版本中提供了多线程升级解决方案:
将同步synchronized替换成现实lock操作。
将Object类中的wait,notify,notifyAll替换成了Condition对象。该对象可以通过Lock锁进行获取。
以下示例实现了本方只唤醒对方线程的操作的优化(原操作为唤醒全部线程)
package com.itheima.test9;
class Resourse
{
private String name;
private int count = 1;
private boolean flag = false;
//使用synchronized同步
public synchronized void set(String name){
while(flag)//如果用if,唤醒阻塞线程的话,不会判断flag,会出现存一次取多次或者存多次取一次的情况。
try{this.wait();}catch (Exception e){}
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"---生产者---"+this.name);
flag = true;
this.notifyAll();//如果只是notify(),存在全部线程阻塞情况。
}
public synchronized void get(){
while(!flag) //如果用if,唤醒阻塞线程的话,不会判断flag,会出现存一次取多次或者存多次取一次的情况。
try{this.wait();}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"------消费者------"+this.name);
flag = false;
this.notifyAll();//如果只是notify(),存在全部线程阻塞情况。
}
}
class Producer implements Runnable
{
Resourse r = new Resourse();
Producer(Resourse r){
this.r = r;
}
public void run(){
while(true){
r.set("商品");
}
}
}
class Consumer implements Runnable
{
Resourse r = new Resourse();
Consumer(Resourse r){
this.r = r;
}
public void run(){
while(true){
r.get();
}
}
}
class ProducerConsumerDemo
{
public static void main(String[] args) throws Exception{
Resourse r = new Resourse();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(pro);
Thread t4 = new Thread(con);
Thread t5 = new Thread(con);
Thread t6 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();//t4.join();主线程放弃执行权,等到t4结束才被重新恢复。t1234交替进行。
t5.start();
t6.start();
}
}
//使用lock进行互斥
package com.itheima.test6;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resourse
{
private String name;
private int count = 1;
private boolean flag = false;
Lock lock=new ReentrantLock();
Condition condition_pro=lock.newCondition();
Condition condition_con=lock.newCondition();
public void set(String name) throwsInterruptedException{
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 synchronized void get() throwsInterruptedException{
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
{
Resourse r = new Resourse();
Producer(Resourse r){
this.r = r;
}
public void run(){
while(true){
try { r.set("商品");}catch(Exception e){}
}
}
}
class Consumer implements Runnable
{
Resourse r = new Resourse();
Consumer(Resourse r){
this.r = r;
}
public void run(){
while(true){
try { r.get();}catch(Exception e){}
}
}
}
class ProducerConsumerDemo2
{
public static void main(String[] args) throws Exception{
Resourse r = new Resourse();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(pro);
Thread t4 = new Thread(con);
Thread t5 = new Thread(con);
Thread t6 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
--------------------------------------------------------------------------------------------------
扩展:
*************************************************
java.lang.Thread setDaemon(boolean on)
将该线程标记为守护线程或用户线程(后台线程)。当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。
参数:
on - 如果为 true,则将该线程标记为守护线程。
*************************************************
join();等待该线程终止。
public final void join()
throwsInterruptedException
当A线程执行到了B线程的join方法时,A线程就会等待。等B线程执行完,A才会执行。
join可以用来临时加入线程执行。
当B线程阻塞时,清除A的Interrupted状态,可以恢复其执行状态。
*************************************************
toString();
public String toString()返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
覆盖:类 Object 中的 toString
返回:该线程的字符串表示形式。
*************************************************
setPriority( int newPriority )
public final void setPriority(int newPriority)更改线程的优先级。
所有线程包括主线程的默认优先级是5,优先级范围为[1,10];
MAX_PRIORITY(10),MIN_PRIORITY(1),NORM_PRIORITY(5),是该Thread类里的常量。
*************************************************
yield()
public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
--------------------------------------------------------------------------------------------------
开发时线程的编写方法:
class ThreadTest{
public static void main(String[] args){
new Thread()[
publicvoid run(){
//执行内容
}
}.start();
Runnable rbl =new Runnable(){
publicvoid run(){
//执行内容
}
};
}
}