线程间通讯
多线程在处理同一资源,但任务却不相同。
示例
package com.monfolld;
public class Resource {
String name;
String sex;
}
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r=r;
}
public void run(){
int x=0;
while (true) {
synchronized (r){
if (x == 0) {
r.name = "mike";
r.sex = "nan";
} else {
r.name = "lili";
r.sex = "nv";
}
x = (x + 1) % 2;
}
}
}
}
class Ouput implements Runnable{
Resource r;
Ouput(Resource r){
this.r=r;
}
public void run(){
while (true){
synchronized (r){
System.out.println(r.name+"........."+r.sex);
}
}
}
}
class ResourceDemo{
public static void main(String[] args){
Resource r=new Resource();
Input in=new Input(r);
Ouput out=new Ouput(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start();
}
}
等待唤醒机制
涉及的方法:
wait():让线程处于冻结状态,被wait的线程会被存储到线程池中
notify():唤醒线程池中的一个线程
notifyAll():唤醒线程池中的所有线程
这些方法都必须定义在同步中,因为这些方法是用于操作线程状态的方法
必须要明确到底操作的是哪个锁上的线程。
为什么这些操作线程的方法定义在了Object类中?因为这些方法是监视器的方法,监视器其实就是锁。锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。
package com.monfolld;
class Resource {
String name;
String sex;
boolean falg=false;
}
class Input extends Resource implements Runnable {
Resource r;
Input(Resource r){
this.r=r;
}
public void run(){
int x=0;
while (true) {
synchronized (r){
if (r.falg)
try {
r.wait();
}catch (InterruptedException e){}
if (x == 0) {
r.name = "mike";
r.sex = "nan";
} else {
r.name = "lili";
r.sex = "nv";
}
r.falg=true;
r.notify();
}
x = (x + 1) % 2;
}
}
}
class Ouput extends Resource implements Runnable {
Resource r;
Ouput(Resource r) {
this.r = r;
}
public void run() {
while (true) {
synchronized (r) {
if (!r.falg)
try {
r.wait();
}catch (InterruptedException e){}
System.out.println(r.name + "........." + r.sex);
r.falg=false;
r.notify();
}
}
}
}
class ResourceDemo{
public static void main(String[] args){
Resource r=new Resource();
Input in=new Input(r);
Ouput out=new Ouput(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start();
}
}
对以上代码进行优化,逻辑完全一样
package com.monfolld;
class Resource {
private String name;
private String sex;
private boolean falg=false;
public synchronized void set(String name,String sex){
if (falg)
try {
this.wait();
}catch (InterruptedException e){}
this.name=name;
this.sex=sex;
falg=true;
this.notify();
}
public synchronized void out(){
if (!falg)
try {
this.wait();
}catch (InterruptedException e){}
System.out.println(name + "........." + sex);
falg=false;
this.notify();
}
}
class Input implements Runnable {
Resource r;
Input(Resource r){
this.r=r;
}
public void run(){
int x=0;
while (true) {
if (x == 0) {
r.set("mike","nan");
} else {
r.set("lili","nv");
}
x = (x + 1) % 2;
}
}
}
class Ouput implements Runnable {
Resource r;
Ouput(Resource r) {
this.r = r;
}
public void run() {
while (true) {
r.out();
}
}
}
class ResourceDemo{
public static void main(String[] args){
Resource r=new Resource();
Input in=new Input(r);
Ouput out=new Ouput(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start();
}
}
多生产者多消费者问题
if:判断标记,只有一次,会导致不该运行的线程运行了,出现了数据错误的情况。
while:判断标记,解决了线程获取执行权后,是否要运行!
notify:只能唤醒一个线程,如果唤醒了本方,没有意义。而且while判断标记加notify会导致死锁。
notifyAll:解决了,本方线程一定会唤醒对方线程。
package com.monfolld;
class Resource1{
private String name;
private int count=1;
private boolean falg=false;
public synchronized void set(String name){
while(falg)
try {
this.wait();
}catch (InterruptedException e){}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
falg=true;
notifyAll();
}
public synchronized void out(){
while (!falg)
try {
this.wait();
}catch (InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"....消费者...."+this.name);
falg=false;
notifyAll();
}
}
class Producer implements Runnable{
private Resource1 r;
Producer(Resource1 r){
this.r=r;
}
public void run(){
while (true){
r.set("烤鸭");
}
}
}
class Consumer implements Runnable{
private Resource1 r;
Consumer(Resource1 r){
this.r=r;
}
public void run(){
while (true){
r.out();
}
}
}
public class ProducerConsumer {
public static void main(String[] args){
Resource1 r=new Resource1();
Producer pro=new Producer(r);
Consumer con=new Consumer(r);
Thread t0=new Thread(pro);
Thread t1=new Thread(pro);
Thread t2=new Thread(con);
Thread t3=new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
jdk1.5以后将同步锁封装成了对象,并将操作锁的隐式方式定义到了对象中,将隐式动作变成了显示动作。
Lock接口:出现代替了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作,同时更为灵活,可以一个锁上加上多组监视器。
lock():获取锁。
unlock():释放锁,通常需要定义finally代码块中。
Condition接口:出现替代了Object中的wait notify notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象,可以将任意锁进行组合。
interface Condition{
await(); //相当于wait();
signal(); //相当于notify();
signalAll(); //相当于notifyAll();
}
package com.monfolld;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource1{
private String name;
private int count=1;
private boolean falg=false;
//创建一个锁
Lock lock=new ReentrantLock();
//通过已有的锁获取该锁上的监视器对象
Condition con=lock.newCondition();
public void set(String name){
lock.lock();
try {
while (falg)
try {
con.await();
}catch (InterruptedException e){}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
falg=true;
con.signalAll();
}
finally {
lock.unlock();
}
}
public void out(){
lock.lock();
try {
while (!falg)
try {
con.await();
}catch (InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"....消费者...."+this.name);
falg=false;
con.signalAll();
}
finally {
lock.unlock();
}
}
}
class Producer implements Runnable{
private Resource1 r;
Producer(Resource1 r){
this.r=r;
}
public void run(){
while (true){
r.set("烤鸭");
}
}
}
class Consumer implements Runnable{
private Resource1 r;
Consumer(Resource1 r){
this.r=r;
}
public void run(){
while (true){
r.out();
}
}
}
public class ProducerConsumer {
public static void main(String[] args){
Resource1 r=new Resource1();
Producer pro=new Producer(r);
Consumer con=new Consumer(r);
Thread t0=new Thread(pro);
Thread t1=new Thread(pro);
Thread t2=new Thread(con);
Thread t3=new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
通过已有的锁获取两组监视器,一组监视生产者,另一组监视消费者
package com.monfolld;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource1{
private String name;
private int count=1;
private boolean falg=false;
//创建一个锁
Lock lock=new ReentrantLock();
//通过已有的锁获取该锁上的监视器对象
//Condition con=lock.newCondition();
//通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者
Condition producer_con=lock.newCondition();
Condition consumer_con=lock.newCondition();
public void set(String name){
lock.lock();
try {
while (falg)
try {
producer_con.await();
}catch (InterruptedException e){}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
falg=true;
consumer_con.signal();
}
finally {
lock.unlock();
}
}
public void out(){
lock.lock();
try {
while (!falg)
try {
consumer_con.await();
}catch (InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"....消费者...."+this.name);
falg=false;
producer_con.signal();
}
finally {
lock.unlock();
}
}
}
class Producer implements Runnable{
private Resource1 r;
Producer(Resource1 r){
this.r=r;
}
public void run(){
while (true){
r.set("烤鸭");
}
}
}
class Consumer implements Runnable{
private Resource1 r;
Consumer(Resource1 r){
this.r=r;
}
public void run(){
while (true){
r.out();
}
}
}
public class ProducerConsumer {
public static void main(String[] args){
Resource1 r=new Resource1();
Producer pro=new Producer(r);
Consumer con=new Consumer(r);
Thread t0=new Thread(pro);
Thread t1=new Thread(pro);
Thread t2=new Thread(con);
Thread t3=new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}
范例
package com.monfolld;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedBuffer {
final Lock lock =new ReentrantLock();
final Condition notFull=lock.newCondition();
final Condition notEmpty=lock.newCondition();
final Object[] items=new Object[100];
int putptr,takeptr,count;
public void put(Object x)throws InterruptedException{
lock.lock();
try {
while (count==items.length)
notFull.await();
items[putptr]=x;
if (++putptr==items.length)putptr=0;
++count;
notEmpty.signal();
}finally {
lock.unlock();
}
}
public Object take()throws InterruptedException{
lock.lock();
try {
while (count==0)
notEmpty.await();
Object x=items[takeptr];
if (++takeptr==items.length)takeptr=0;
--count;
notFull.signal();
return x;
}finally {
lock.unlock();
}
}
}
wait和sleep的区别
1.wait可以指定时间也可以不指定。
sleep必须指定时间。
2.在同步中,对cpu的执行权和锁的处理不同。
wait:释放执行权,释放锁。
sleep:释放执行权,不释放锁。
停止线程方式-定义标记
1.stop方法结束 已过时,不安全。
2.run方法结束
任务中都会有循环结构,只要控制循环就可以结束任务,控制循环通常就用定义标记来完成。
但是如果线程处于了冻结状态,无法读取标记,可以用interrupt()方法将线程从冻结状态前置回复到运行状态中来,让线程具备cpu的执行资格。
但是强制动作会发生InterruptedException,记得要处理
3.setDaemon守护线程 当正在运行的线程都是守护线程时,java虚拟机退出。该方法必须在启动线程前调用。
其他方法
1.join方法 给予执行权,等待该线程终止
2.setPtiority(Thread.MAX_PRIORITY)方法 设置线程优先级
3.yield()方法 暂停当前正在执行的线程对象,并执行其他线程。
细节错误示例
下列代码如果发生错误,错误在哪一行?
public class Testy implements Runnable{
public void run(Thread thread){
}
}
错误在第一行,应该被abstract 修饰。
下面代码的输出
class ThreadTest{
public static void main(String[] args){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("runable run");
}
})
{
public void run(){
System.out.println("subThread run");
}
}.start();
}
}
结果以子类为主,也就是输出subThread run,子类没有的话,以任务为主输出runable run,如果任务也没有,以Thread类自己为主。
Runable和Thread的区别:
1.一个类只能继承一个类,类继承了Thread就不能继承其他的类。
实现了Runable接口,还能实现其他的接口。
2.Runable提高了程序的扩展性,降低了程序的耦合性,设置线程任务和开启新的线程进行了分离。
新的线程能够直接开启。实现类中,重写了run方法,创建thread对象,start开启线程。