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是线程t1,main是主线程,如图所示,当t1执行完后主线程才执行
多线程-优先级&yield()方法
优先级:(1~10 1优先级最小,10优先级最大)
线程的优先级(Priority)告诉调试程序该线程的重要程度有多大。如果有大
量线程都被堵塞,都在等候运行,调试程序会首先运行具有最高优先级的那个线程。然
而,这并不表示优先级较低的线程不会运行(换言之,不会因为存在优先级而导致死锁)。
若线程的优先级较低,只不过表示它被准许运行的机会小一些而已。
可用getPriority()方法读取一个线程的优先级,并用setPriority()改变它。
使用方法:例如:Thread对象.getPriority(MAX_PRIORITY);
yield():
暂停当前正在执行的线程对象,并执行其他线程。
它与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级
的线程有执行的机会。
使用方法:写在run()方法中,Thread.yield();