多线程
Thread和Runnable的区别
- 一般使用Runnable,因为可以避免单继承的局限性。
- Runnable可以更方面的体现数据共享的概念(但不是说Thread类不能实现数据共享)
线程的状态转换
-
创建状态:
创建了一个线程对象后,如Thread thread = new Thread();此时,已经有了相应的内存空间和资源,但是还处于不可运行的状态 -
就绪状态:
调用线程的start()启动线程,进入线程队列排队,具备了运行条件,等待CPU的执行时间片 -
运行状态:
获得CPU时间片,并调用了run()。 -
阻塞状态:
运行状态中的线程,被人为挂起或者调用了sleep()、wait()、suspend(),线程进入阻塞状态。将让出CPU执行权并暂时中止自己的执行。阻塞时,线程不能进入排队队列,只有当引起阻塞的原因消除后,线程才可以进入就绪状态。 -
终止状态:
调用stop()或者run()执行结束后,处于该状态。处于该状态的线程不再具有继续运行的能力。
public class Temp {
private int mCurrentNum;
private final int MAX = 10;
public static void main(String[] args) {
Producer producer = new Producer();
new Thread(producer,"Thread111").start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
producer.run();
// 输出:
// Thread111
// main
}
}
class Producer implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
死锁
所谓死锁,就是两个线程都在等待彼此的锁,造成了程序的停滞状态。一般是过多的同步导致的。生活中的例子:小孩A想要小孩B的玩具,小孩B想要小孩A的连环画,A对B说:“你把玩具给我,我就把连环画给你”,B不服气道:“你先把你的连环画给我,我才给你玩具”,就这样,双方都在等待在对方的答复(锁),僵持不下:
public class Temp {
public static void main(String[] args) {
DeadLock lock1 = new DeadLock();// 因为两个锁对象都是static,所以可体现共享
DeadLock lock2 = new DeadLock();
lock1.flag = true;
new Thread(lock1).start();
lock2.flag =false;
new Thread(lock2).start();
}
}
class DeadLock implements Runnable{
private static A a = new A();// 为了让其唯一,置为static
private static B b = new B();// 为了让其唯一,置为static
public boolean flag;//用于判断谁先执行
@Override
public void run() {
if (flag) {
synchronized (a){
a.say();
try {
Thread.sleep(500);// 为了更好的模拟效果,此处休眠500ms
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
a.get();
}
}
} else {
synchronized (b){
b.say();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a){
b.get();
}
}
}
}
}
class A{
public void say(){
System.out.println("A对B说:“你把玩具给我,我就把连环画给你”");
}
public void get(){
System.out.println("A得到玩具");
}
}
class B{
public void say(){
System.out.println("B对A说:“你先把你的连环画给我,我才给你玩具”");
}
public void get(){
System.out.println("B得到连环画");
}
}
sleep()和wait()区别
sleep()是Thread的静态方法,导致线程以指定时间暂停执行,把CPU执行权让给其他线程,但是监控状态依然保持,到时后,会自动恢复。并且不释放对象锁。
wait()用在同步块或者同步方法内,Object的方法,表示线程等待,让出同步的锁,并进入等待此对象锁的等待锁定池,只有针对此锁的对象发出notify()或者notifyAll()后,才有机会继续执行。释放锁。
生产者消费者问题
public class Temp {
private int mCurrentNum;
private final int MAX = 10;
public static void main(String[] args) {
Temp temp = new Temp();
new Thread(temp.new Producer()).start();
new Thread(temp.new Consumer()).start();
new Thread(temp.new Producer()).start();
new Thread(temp.new Consumer()).start();
new Thread(temp.new Producer()).start();
new Thread(temp.new Consumer()).start();
new Thread(temp.new Producer()).start();
new Thread(temp.new Consumer()).start();
}
public class Producer implements Runnable {
@Override
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (Temp.this) {
while (mCurrentNum == MAX) {// 缓存区已满,停止生产
try {
Temp.this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mCurrentNum++;
System.out.println("生产者"+Thread.currentThread().getName()+"生产,产品总数为:"+mCurrentNum+" 个物品");
Temp.this.notifyAll();
}
}
}
}
public class Consumer implements Runnable {
@Override
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (Temp.this) {
while (mCurrentNum == 0) {// 缓存区没有数据,停止消费
try {
Temp.this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mCurrentNum--;
System.out.println("消费者"+Thread.currentThread().getName()+"消费,剩余产品总数为:"+mCurrentNum+" 个物品");
Temp.this.notifyAll();
}
}
}
}
}
生产者消费者存在的问题:
- 设置的数据错位了,可依靠同步解决
- 数据会重复取出和重复设置,依靠wait()、notify()机制解决
操作流程如下:
public class Temp {
public static void main(String[] args) {
Message message = new Message();
new Thread(new Producer(message)).start();
new Thread(new Consumer(message)).start();
}
}
class Message{
private String title;
private String content;
private boolean flag = true;// ture:表示可以生产,但不能取走;false相反
public synchronized void set(String title,String content){
if (!flag) {//已经生产过了,不生产
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.title = title;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content;
this.flag = false;// 生产完成,修改标志位
notifyAll();// 通知消费者,取走
}
public synchronized void get(){
if (flag) {//未生产,不取走
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.title+"-->"+this.content);
this.flag = true;
notifyAll();
}
}
class Producer implements Runnable {
private Message msg = null;
public Producer(Message msg){
this.msg= msg;
}
@Override
public void run() {
for (int i = 0;i < 50;i++){
if (i % 2 == 0) {
this.msg.set("aaa", "111");
} else {
this.msg.set("bbb","222");
}
}
}
}
class Consumer implements Runnable{
private Message msg = null;
public Consumer(Message msg){
this.msg = msg;
}
@Override
public void run() {
for (int i = 0;i < 50 ; i++){
this.msg.get();
}
}
}