Java基础-知识点总结-Java线程间通信

Java线程间通信

 

 线程间通信

 

      多个线程在操作同一个资源,但是操作的动作不同

 

      示例代码:

 

 

class Res // 资源
{
	private String name;
	private String sex;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getSex() {
		return sex;
	}
}

class Input implements Runnable // 对资源进行写操作
{
	private Res r;

	public Input(Res r) {
		this.r = r;
	}

	public void run() {
		int x = 0;
		while (true) {
			synchronized (r) {
				if (x == 0) {
					r.setName("Mike");
					r.setSex("man");
				} else {
					r.setName("张三");
					r.setSex("女");
				}
				x = (x + 1) % 2;
			}
		}
	}
}

class Output implements Runnable // 对资源进行读操作
{
	private Res r;

	public Output(Res r) {
		this.r = r;
	}

	public void run() {
		while (true) {
			synchronized (r) {
				System.out.println(r.getName() + "....." + r.getSex());
			}
		}
	}
}

class InputOutputDemo {
	public static void main(String[] args) {
		Res r = new Res();
		Input in = new Input(r);
		Output o = new Output(r);
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(o);
		t1.start();
		t2.start();
	}
}

 

 

 

 线程通信-等待唤醒机制

 

class Res // 资源类
{
	private String name;
	private String sex;
	public boolean flag = false; // 标识位,用于判定那个线程等待

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getSex() {
		return sex;
	}
}

class Input implements Runnable {
	private Res r;

	public Input(Res r) {
		this.r = r;
	}

	public void run() {
		int x = 0;
		while (true) {
			synchronized (r) {
				if (r.flag) // flag为真,则线程Input等待
					try {
						r.wait();
					} catch (Exception e) {
					}
				if (x == 0) {
					r.setName("Mike");
					r.setSex("man");
				} else {
					r.setName("张三");
					r.setSex("女");
				}
				x = (x + 1) % 2;
				r.flag = true; // 将标识位改为true
				r.notify(); // 唤醒线程Output
			}
		}
	}
}

class Output implements Runnable {
	private Res r;

	public Output(Res r) {
		this.r = r;
	}

	public void run() {
		while (true) {
			synchronized (r) {
				if (!r.flag) // flag为假,则线程Output等待
					try {
						r.wait();
					} catch (Exception e) {
					}
				System.out.println(r.getName() + "....." + r.getSex());
				r.flag = false; // 将标识位改为false
				r.notify(); // 唤醒线程Input
			}
		}
	}
}

class InputOutputDemo01 {
	public static void main(String[] args) {
		Res r = new Res();
		Input in = new Input(r);
		Output o = new Output(r);
		Thread t1 = new Thread(in);
		Thread t2 = new Thread(o);
		t1.start();
		t2.start();
	}
}

 

 

 

总结:

 

      wait():让本线程等待

 

      notify():唤醒一个同一个锁中的其他线程

 

      notifyAll():唤醒同一个锁中的其他所有线程

 

      这三个方法都用在同步中,因为要对持有监视器(锁)的线程操作,而同步中才有锁

 

      这些方法在操作同步中的线程时,都必须要标识它们所操作线程持有的锁,即

 

      锁.wait();/锁.notify();/锁.notifyAll();同一个锁上的等待的线程,只能被同一个锁上

 

      Notify()方法唤醒,不能被其他锁中的线程唤醒,也就是说,等待和唤醒必须在同

 

      一个锁中

 

   这些操作线程的方法都定义在Object类中,因为锁可以是任意对象,所以被任意

 

      对象调用的方法定义在Object类中。

 

线程间通信-生产者消费者

      方式一:

 

 

class Resource {
	private String name;
	private int n = 1;
	private boolean flag = false;

	public synchronized void set(String name) {
		while (flag)
			// 循环判断资源是否为空,不为空则等待
			try {
				this.wait();
			} catch (Exception e) {
			}
		this.name = name + "_" + n++;
		System.out.println(Thread.currentThread().getName() + "...生产者..."
				+ this.name);
		this.flag = true;
		this.notifyAll(); // 唤醒其他所有线程
	}

	public synchronized void out() {
		while (!flag)
			// 循环判断是否为空,若不为则等待
			try {
				this.wait();
			} catch (Exception e) {
			}
		System.out.println(Thread.currentThread().getName() + " 消费者 " + name);
		flag = false;
		this.notifyAll(); // 唤醒其他线程
	}
}

class Producer implements Runnable {
	private Resource res;

	public Producer(Resource res) {
		this.res = res;
	}

	public void run() {
		while (true)
			res.set("面包");
	}
}

class Consumer implements Runnable {
	private Resource res;

	public Consumer(Resource res) {
		this.res = res;
	}

	public void run() {
		while (true)
			res.out();
	}
}

class ProducerConsumerDemo03 {
	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(con);
		Thread t3 = new Thread(pro);
		Thread t4 = new Thread(con);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

 

 

 

方式二:

 

JDK 1.5中提供了多线程升级解决方案

 

将同步synchronized替换成显示的Lock操作

 

将Object类中的wait,notify,notifyAll替换成Condition对象

 

分别对应await,signal,signalAll

 

该对象可以以Lock锁获取 Lock对象.newCondition();

 

该方案实现了只唤醒对方线程,不唤醒同类线程

 

import java.util.concurrent.locks.*;

class Resource {
	private String name;
	private int n = 1;
	private boolean flag = false;
	final private Lock lock = new ReentrantLock();
	private Condition condition_p = lock.newCondition();
	private Condition condition_c = lock.newCondition();

	public void set(String name) throws InterruptedException {
		lock.lock();
		try {
			while (flag)
				condition_c.await();
			this.name = name + "_" + n++;
			System.out.println(Thread.currentThread().getName()
					+ "......生产者......" + this.name);
			this.flag = true;
			condition_p.signal();
		} finally {
			lock.unlock();
		}
	}

	public synchronized void out() throws InterruptedException {
		lock.lock();
		try {
			while (!flag)
				condition_p.await();
			System.out.println(Thread.currentThread().getName() + " 消费者 "
					+ this.name);
			this.flag = false;
			condition_c.signal();
		} finally {
			lock.unlock();
		}
	}
}

class Producer implements Runnable {
	private Resource res;

	public Producer(Resource res) {
		this.res = res;
	}

	public void run() {
		while (true) {
			try {
				res.set("面包");
			} catch (InterruptedException e) {
			}
		}
	}
}

class Consumer implements Runnable {
	private Resource res;

	public Consumer(Resource res) {
		this.res = res;
	}

	public void run() {
		while (true)
			try {
				res.out();
			} catch (InterruptedException e) {
			}
	}
}

class ProducerConsumerDemo07 {
	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(con);
		Thread t3 = new Thread(pro);
		Thread t4 = new Thread(con);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

 

 

 

 

 

 停止线程

 

      停止线程只有一种方法,就是让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;
	}
}

class StopThreadDemo01 {
	public static void main(String[] args) {
		StopThread s = new StopThread();
		Thread t1 = new Thread(s);
		Thread t2 = new Thread(s);
		t1.start();
		t2.start();
		int x = 0;
		while (true) {
			if (x++ == 60) {
				t1.interrupt(); // interrupt()方法 用于将线程的中断清除,使其
				t2.interrupt(); // 恢复到运行状态,并抛出InterruptedExceeption异常
				break;
			}
			System.out.println(Thread.currentThread().getName() + "...run" + x);
		}
		System.out.println("over");
	}
}

 

 

 

Interrupt():如果线程在调用Object类的wait()wait(long)

 

wait(long, int)方法,或者该类的join()join(long)join(long, int)

 

sleep(long)sleep(long, int)方法过程中受阻,则其中断状态将被清除,它

 

还将收到一个InterruptedException

 

 多线程-守护线程

 

      Thread类中提供了setDeanon(Booleanon)方法,该方法可将线程设置为守护线程

 

(用户线程),这种线程在运行过程中,当正在运行得线程都是守护线程时,JVM

 

虚拟机退出,程序结束。

 

注意:

 

该方法必须在县城启动前调用

 

class StopThread implements Runnable {
	private boolean flag = true;

	public synchronized void run() {
		while (flag) {
			System.out.println(Thread.currentThread().getName() + "...run");
		}
	}

	public void changeFlag() {
		flag = false;
	}
}

class StopThreadDemo02 {
	public static void main(String[] args) {
		StopThread s = new StopThread();
		Thread t1 = new Thread(s);
		Thread t2 = new Thread(s);
		t1.setDaemon(true); // 将线程设置为守护线程
		t2.setDaemon(true);
		t1.start();
		t2.start();
		int x = 0;
		while (true) {
			if (x++ == 60) {
				break;
			}
			System.out.println(Thread.currentThread().getName() + "...run" + x);
		}
		System.out.println("over");
	}
}

 

 

 

 多线程-join()方法

 

      join()方法:用法是线程.join();作用是等待该线程终止

 

      特点:

 

      A线程执行到了B线程.join()时,A线程就会等待,等到B线程执行完,才会执行

 

      Join()可以用来临时加入线程执行

 

class Demo implements Runnable
{
		public void run()
		{
			for(int x = 0;x < 60;x++)
				System.out.println(Thread.currentThread().getName()+"..."+x);
		}
}
class JoinDemo
{
		public static void main(String [] args) throws InterruptedException
		{
			Demo d = new Demo();
			Thread t1 = new Thread(d);
			Thread t2 = new Thread(d);
			t1.start();
			t2.start();
			t1.join();
			for(int x = 0; x < 60;x++)
				System.out.println(Thread.currentThread().getName()+"..."+x);
			System.out.println("over");
		}
}

 

 

 

运行结果如图:


 

Thread-1是线程t1main是主线程,如图所示,当t1执行完后主线程才执行

 

 多线程-优先级&yield()方法

 

      优先级:(1~10     1优先级最小,10优先级最大)

 

线程的优先级(Priority)告诉调试程序该线程的重要程度有多大。如果有大

 

      量线程都被堵塞,都在等候运行,调试程序会首先运行具有最高优先级的那个线程。然

 

      而,这并不表示优先级较低的线程不会运行(换言之,不会因为存在优先级而导致死锁)。

 

      若线程的优先级较低,只不过表示它被准许运行的机会小一些而已。

 

      可用getPriority()方法读取一个线程的优先级,并用setPriority()改变它。

 

      使用方法:例如:Thread对象.getPriority(MAX_PRIORITY);

 

      yield()

 

      暂停当前正在执行的线程对象,并执行其他线程。

 

      它与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级

 

      的线程有执行的机会。

 

      使用方法:写在run()方法中,Thread.yield();


 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值