Java:多线程
1、什么是线程?
在说线程之前,我们有必要了解下什么是进程,那什么是进程呢?
进程就是当我们打开一个计算机软件或者执行一个程序时,在计算机中运行的反映,线程依托进程,而一个进程中至少有一个线程,比如JVM是一个进程,而它至少有一个主线程在CPU中执行,不然不可能启动JVM,另外也有一个垃圾回收的线程在运行。可以在任务管理器里面查看到的那些就是进程 如下:
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
单线程:就比如当我们打开电脑管家或者类似的软件,执行里面的清理垃圾这个线程,只有在本次执行完成后才可以点击再执行,在本次为执行完成之前,你继续点击是没有反应的,单线程简单就是这么理解。
多线程:如果程序中只有单线程,效率会变的很低,就好比生活中在车站的售票窗口,如果就只有一个售票窗口,这样效率特别低,但是真实却是有多个售票窗口,多线程就好比这个多售票窗口,在java中提供了并发机制,而程序员所要做的就是保证这些多线程所访问的共享数据的安全性,这就是多线程编程,线程一增多,也会越来越复杂!
2、java多线程的实现方式
参考http://c.biancheng.net/view/1159.html
3、Java对于多线程的安全问题提供了专业的解决方式
就是同步代码块。
synchronized(对象){
需要被同步的代码
}
对象如同锁。持有锁的线程可以在同步中执行。
没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
同步的前提:
1)必须要有两个或者两个以上的线程。
2)必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程在运行。
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源,
4、线程的状态
参考https://www.runoob.com/java/java-multithreading.html
5、CPU的随机性造成的问题
多线程具备随机性。因为是由cpu不断的快速切换造成的。就有可能会产生多线程的安全问题。
问题的产生的原因:
几个关键点:
1,多线程代码中有操作共享数据。
2,多条语句操作该共享数据。
当具备两个关键点时,
有一个线程对多条操作共享数据的代码执行的一部分。还没有执行完,另一个线程开始参与执行。
就会发生数据错误。
解决方法:
当一个线程在执行多条操作共享数据代码时,其他线程即使获取了执行权,也不可以参与操作。
Java就对这种解决方式提供了专业的代码。
同步
同步的原理:就是将部分操作功能数据的代码进行加锁。
同步的表现形式:
1,同步代码块。
2,同步函数。
两者有什么不同:
同步代码块使用的锁是任意对象。
同步函数使用的锁是this。
注意:对于static的同步函数,使用的锁不是this。是 类名.class 是该类的字节码文件对象。
涉及到了单例设计模式的懒汉式。
同步的好处:解决了线程的安全问题。
弊端:
较为消耗资源。
同步嵌套后,容易死锁。
要记住:同步使用的前提:
1,必须是两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。
这是才可以称为这些线程被同步了。
死锁代码一定会写。但开发时一定注意避免
#第二重点:同步的所有特性 #
Sleep() wait() notify() notifAll()
JDK1.5 中提供了多线程升级解决方案。
将同步Synchronized替换成现实Lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁 进行获取。
Lock:替代了Synchronized
lock
unlock
newCondition()
Condition:替代了Object wait notify notifyAll
await();
signal();
signalAll();
生产者消费者模式示例:
import java.util.concurrent.locks.*; public class ProducerConsumerDemo2 { public static void main(String[] args) { Resource r = new Resource(); Producer2 pro = new Producer2(r); Consumer2 con = new Consumer2(r); Thread t1 = new Thread(pro); Thread t2 = new Thread(pro); Thread t3 = new Thread(con); Thread t4 = new Thread(con); t1.start(); t2.start(); t3.start(); t4.start(); } } /* JDK1.5 中提供了多线程升级解决方案。 将同步Synchronized替换成现实Lock操作。 将Object中的wait,notify notifyAll,替换了Condition对象。 该对象可以Lock锁 进行获取。 该示例中,实现了本方只唤醒对方操作。 Lock:替代了Synchronized lock unlock newCondition() Condition:替代了Object wait notify notifyAll await(); signal(); signalAll(); */ class Resource { private String name; private int count = 1; private boolean flag = false; // t1 t2 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();//t1,t2 this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name); flag = true; condition_con.signal(); } finally { lock.unlock();//释放锁的动作一定要执行。 } } // t3 t4 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 Producer2 implements Runnable { private Resource res; Producer2(Resource res) { this.res = res; } public void run() { while(true) { try { res.set("+商品+"); } catch (InterruptedException e) { } } } } class Consumer2 implements Runnable { private Resource res; Consumer2(Resource res) { this.res = res; } public void run() { while(true) { try { res.out(); } catch (InterruptedException e) { } } } }
输出结果
中断线程
stop方法已经过时。
如何停止线程?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:
当线程处于了冻结状态。
就不会读取到标记。那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。
强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。
Thread类提供该方法 interrupt();
join:
当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。
join可以用来临时加入线程执行。