java 线程死锁

死锁:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不能正常运行。简单的说就是:线程死锁时,第一个线程等待第二个线程释放资源,而同时第二个线程又在等待第一个线程释放资源。 导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问

线程间通信:就是多个线程在线程在操作同一个资源,但是操作的动作不同

下面是两个线程间的通信的例子,如果不使用同步,则name和sex可能不同步:

class Res {      //共享的资源
	String name;
	String sex;
}
class Input implements Runnable {   //--------------使用1
	private Res r;
	Input(Res r) {
		this.r = r;
	}
	public void run() {
		int x = 0;
		while (true) {
			synchronized (Input.class) {  // 而下面必须也是Input.class 或者是Output.class,总之上下两个线程锁必须一致才可以同步
				if (x == 0) {
					r.name = "mike";
					r.sex = "man";
				} else {
					r.name = "丽丽";
					r.sex = "女女女女";
				}
				x = (x + 1) % 2;
			}
		}
	}
}

class Output implements Runnable {
	private Res r;
	Output(Res r) {
		this.r = r;
	}
	public void run() {
		while (true)
			synchronized (Input.class) {
				System.out.println(r.name + "----" + r.sex);
			}
	}
}
public class Test {
	public static void main(String[] args) {
		Res r = new Res();
		Input in = new Input(r);
		Output out = new Output(r);

		Thread t1 = new Thread(in), t2 = new Thread(out);
		t1.start();t2.start();
	}
}
结果:丽丽----女女女女
丽丽----女女女女
丽丽----女女女女
mike----man
mike----man


wait(),notify(),notifyAll()

这三个方法用于协调多个线程对共享数据的存取,所以必须在Synchronized语句块内使用这三个方法。Synchronized用于保护共享数据,但是这样程序的流程就很不灵活了,此时用这三个方法来灵活控制。 
线程可以调用对象的wait()方法使当前线程暂停执行并释放对象锁标志,进入等待状态,并且可以调用notify()或者notifyAll()方法通知正在等待的其他线程,然后等待同一个线程锁的notify,继续执行wait后未执行完的内容。notify()通知等待队列中的第一个线程,notifyAll()通知的是等待队列中的所有线程。 
注意 这三个方法都是java.lang.Ojbect的方法! 为什么这些操作线程的方法要定义在Object中?因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。不可以对不同锁中线程唤醒。也就是说,等待和唤醒必须是同一个锁,而锁可以是任意对象,所以可以被任意对象调用的方法定义Object中
 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个。
把上面例子的输出改为交替输出:

class Res { // 共享的
	String name;
	String sex;
	boolean flag = false;
}

class Input implements Runnable {
	private Res r;

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

	public void run() {
		int x = 0;
		while (true) {
			synchronized (r) {
				if (r.flag)
					try { // --------接口exception不能拋
						r.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				if (x == 0) {
					r.name = "mike";
					r.sex = "man";
				} else {
					r.name = "丽丽";
					r.sex = "女女女女";
				}
				x = (x + 1) % 2;
				r.flag = true;
				r.notify();
			}
		}
	}
}

class Output implements Runnable {
	private Res r;
	Output(Res r) {
		this.r = r;
	}
	public void run() {
		while (true)
			synchronized (r) {
				if (!r.flag)
					try {
						r.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				System.out.println(r.name + "----" + r.sex);
				r.flag = false;
				r.notify();
			}
	}
}

public class Test {
	public static void main(String[] args) {
		Res r = new Res();
		Input in = new Input(r);
		Output out = new Output(r);

		Thread t1 = new Thread(in), t2 = new Thread(out);
		t1.start();t2.start();
	}
}
下面是生产者、消费者问题(多个生产者、消费者),每产生一个产品就消费一个

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

	public synchronized void set(String name) {
		while (flag)
			try {
				wait();
			} catch (Exception e) {
			}
		this.name = name + "----" + count++;
		System.out.println(Thread.currentThread().getName() + "----生产者----"+ this.name);
		flag = true;
		this.notifyAll();
	}

	public synchronized void out() {
		while (!flag)
			try {
				wait();
			} catch (Exception e) {
			}
		System.out.println(Thread.currentThread().getName()+ "----消费者---------" + this.name);
		flag = false;
		this.notifyAll();// 由notify换成notifyAll
	}
}

class Producer implements Runnable {
	private Resource res;
	Producer(Resource res) {
		this.res = res;
	}
	public void run() {
		while (true)
			res.set("+商品+");
	}
}

class Consumer implements Runnable {
	private Resource res;
	Consumer(Resource res) {
		this.res = res;
	}
	public void run() {
		while (true)
			res.out();
	}
}

class Test {
	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),t2 = new Thread(pro),t3 = new Thread(con),t4 = new Thread(con);
		t1.start();t2.start();t3.start();t4.start();
	}
}
虽然 synchronized 方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。jdk1.5中提供了多线程升级解决方案,将同步synchronized替换成现实Lock操作 ,将Object中的wait,notify,notifyAll替换成Condition对象, Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用

以下用lock实现生产者消费者

import java.util.concurrent.locks.*;
class Resource {
	private String name;
	private int count = 1;
	private boolean flag = false;

	private Lock lock = new ReentrantLock();// //
	private Condition condition_pro = lock.newCondition();// /
	private Condition condition_con = lock.newCondition();// //

	public void set(String name) throws InterruptedException {
		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 void out() throws InterruptedException {
		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 {
	private Resource res;
	Producer(Resource res) {
		this.res = res;
	}

	public void run() {
		while (true)
			try {
				res.set("+商品+");
			} catch (Exception e) {
			}
	}
}

class Consumer implements Runnable {
	private Resource res;
	Consumer(Resource res) {
		this.res = res;
	}

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

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

 如何线程中断:定义循环结束标记,因为线程的代码一般都是循环,只要控制了循环即可; 特殊情况下,当冻结后,标记无法读取,使用interrupt()方法,结束线程的冻结状态,使线程回到运行状态来,但会产生InterruptedException异常

stop方法已经不再使用

interrupt(): 如果线程在调用 Object 类的 wait()、wait(long)或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。

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 Test {
	public static void main(String[] args) {
		StopThread st = new StopThread();
		Thread t1 = new Thread(st),t2 = new Thread(st);

		t1.start();t2.start();
		int num = 0;
		while (true) {
			if (num++ == 60) {
				// st.changeFlag();
				t1.interrupt();
				t2.interrupt();
				break;
			}
			System.out.println(Thread.currentThread().getName() + "-----" + num);
		}
		System.out.println("over");
	}
}

后台线程:setDaemon(boolean on)将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,程序结束,Java 虚拟机退出。 

yield() sleep() wait() 区别

sleep() 
 
  使当前线程暂停执行一段时间,让其他线程有机会继续执行,只是轮到它执行时,它不执行run方法只是在那暂停了对cpu的调度没影响,但它并不释放对象锁。也就是如果           有Synchronized同步块,其他线程仍然不同访问共享数据。
join()  t.join(),正在运行的线程在t线程运行结束后执行,也就是等待调用该方法的线程执行完毕后再往下继续执行,如果有多个线程,不影响其它线程。
yield()   与sleep()类似,只是不能由用户指定暂停多长时间 
wait()  wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用

你可能感兴趣的:(Java)