进程与线程
进程:是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
线程:是操作系统能够进行运算调度的最小单位。它被包含在进程 之中,是进程中的实际运作单位。
每个程序都是一个进程 ,一个进程里面可以包含多个线程 。(比如你在听歌的时候是一个线程,下载音乐又是另一个线程,它们不会互相干扰),线程之间可以共享进程的资源。
Java多线程
1、继承Thread Thread常用的方法
Modifier and Type
Method
Description
void
start()
导致此线程开始执行; Java虚拟机调用此线程的run
方法。
static void
sleep(long millis)
使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。 会占用线程的睡眠
void
join()
等待这个线程死亡。
static void
yield()
对调度程序的一个暗示,即当前线程愿意产生当前使用的处理器。
void
run()
如果这个线程使用单独的Runnable
运行对象构造,则调用该Runnable
对象的run
方法; 否则,此方法不执行任何操作并返回。
更多方法请查阅官方API文档
继承Thread需要重写它的run 方法,调用时用start方法才能启动线程。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ThreadTest { public static void main (String[] args) { count count1=new count(); count count2=new count(); count1.start(); count2.start(); } } class count extends Thread { @Override public void run () { for (int i=0 ;i<100 ;i++) { System.out.println(Thread.currentThread().getName()+":" +i); } } }
部分-返回结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Thread-0 :64 Thread-0 :65 Thread-0 :66 Thread-0 :67 Thread-0 :68 Thread-0 :69 Thread-0 :70 Thread-0 :71 Thread-1 :3 Thread-1 :4 Thread-0 :72 Thread-1 :5 Thread-0 :73 Thread-1 :6 Thread-0 :74 Thread-1 :7 Thread-0 :75 线程0 和线程1 互相交叉运行互不阻塞。
查看线程状态
程序路径: %JAVA_HOME%/bin/jvisualvm.exe
2、实现Runnable接口 其实Thread也是实现了Runnable接口,所以只需要把run方法重写就行了 让Thread去调用。只不过Thread需要继承而Runnable是接口。(好处自己回顾一下面向对象知识)
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class RunnableTest { public static void main (String[] args) { count count1=new count(); count count2=new count(); new Thread(count1).start(); new Thread(count2).start(); } } class count implements Runnable { @Override public void run () { for (int i=0 ;i<100 ;i++) { try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":" +i); } } }
部分-返回结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Thread-0:26 Thread-1:27 Thread-0:27 Thread-1:28 Thread-0:28 Thread-1:29 Thread-0:29 Thread-1:30 Thread-0:30 Thread-1:31 Thread-0:31 Thread-1:32 Thread-0:32 Thread-1:33 Thread-0:33 Thread-1:34 Thread-0:34 线程0和线程1互相交叉运行互不阻塞。
多线程的锁 给我一把锁,我能创造出一种规则。
线程异步会造成不安全,比如下方图 value两次++ 值应该改变为12。
原因:线程1 读取时 value还是10,因为计算机调度快 线程2也马上可以读取value等于10 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class countVlaue { public static void main (String[] args) { Test Test=new Test(); new Thread(Test).start(); new Thread(Test).start(); } } class Test implements Runnable { int vlaue=10 ; @Override public void run () { try { Thread.sleep(3000 ); } catch (InterruptedException e) { e.printStackTrace(); } vlaue++; System.out.println(vlaue); } }
输出结果:
Synchronized 的解析 在Hotspot虚拟机中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充;Java对象头是实现synchronized的锁对象的基础,一般而言,synchronized使用的锁对象是存储在Java对象头里。
实现原理: JVM 是通过进入、退出 对象监视器(Monitor) 来实现对方法、同步块的同步的,而对象监视器的本质依赖于底层操作系统的 互斥锁(Mutex Lock) 实现。
Synchronized 的使用
Synchronized 用于线程同步,避免线程共享资源的异常。
Synchronized 可用于方法锁、代码块锁、类锁。
Synchronized 默认为Synchronized (this) 参数为对象,静态类锁 参数为Synchronized(类.class)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class countVlaue { public static void main (String[] args) { Test Test=new Test(); new Thread(Test).start(); new Thread(Test).start(); } } class Test implements Runnable { int vlaue=10 ; @Override public synchronized void run () { try { Thread.sleep(3000 ); } catch (InterruptedException e) { e.printStackTrace(); } vlaue++; System.out.println(vlaue); } }
输入结果:
ReentrantLock的使用 主要的方法
Modifier and Type
Method
Description
void
lock()
获得锁。
void
unlock()
尝试释放此锁。
更多方法请查阅官方API文档
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.concurrent.locks.ReentrantLock;public class countVlaue { public static void main (String[] args) { Test Test=new Test(); new Thread(Test).start(); new Thread(Test).start(); } } class Test implements Runnable { int vlaue=10 ; ReentrantLock lock=new ReentrantLock(); @Override public void run () { try { lock.lock(); vlaue++; System.out.println(vlaue); Thread.sleep(3000 ); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } }
输入结果:
死锁:两个线程互相占用对方需要的锁,会造成卡顿现象。
线程池 好处:提高响应速度、降低资源消耗、便于管理。
相关API:ExecutorService 和Executors
消费者与生产者模式 业务需求 背景:消费者到肯德基店购买鸡,但是肯德基不能现杀鸡需要准备货物才能运营给消费者消费,所以消费者就必须等待并告诉肯德基需要准备货物。
肯德基是供应商,如果只生产鸡没有去宣传告诉消费者那永远运营不起来。
(鸡不可能 同时生产 同时消费)
方法
Modifier and Type
Method
Description
void
wait()
释放锁并阻塞但并不会持有锁
void
notify()
唤醒某一条线程 未必唤醒成功
void
notifyAll()
唤醒全部线程
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 public class PC { public static void main (String[] args) { Cache Cache=new Cache(); new Producer(Cache).start(); new Consumer(Cache).start(); } } class Producer extends Thread { Cache cache; public Producer (Cache cache) { this .cache = cache; } @Override public void run () { for (int i = 0 ; i < 15 ; i++) { cache.push(i); System.out.println("生产第" + i + "只" ); } } } class Consumer extends Thread { Cache cache; public Consumer (Cache cache) { this .cache = cache; } @Override public void run () { for (int i = 0 ; i < 15 ; i++) { System.out.println("消费第" + cache.pop().id + "只" ); } } } class chicken { int id; public chicken (int id) { this .id = id; } } class Cache { private chicken[] chickens = new chicken[10 ]; public static int count = 0 ; public synchronized void push (int id) { if (count == chickens.length) { try { this .wait(); } catch (InterruptedException e) { e.printStackTrace(); } } chicken chicken = new chicken(id); chickens[count++] = chicken; this .notifyAll(); } public synchronized chicken pop () { chicken chicken = null ; if (count == 0 ) { try { this .wait(); } catch (InterruptedException e) { e.printStackTrace(); } } count--; chicken = chickens[count]; this .notifyAll(); return chicken; } }
输出结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 生产第0 只 生产第1 只 生产第2 只 生产第3 只 生产第4 只 生产第5 只 生产第6 只 生产第7 只 生产第8 只 生产第9 只 生产第10 只 消费第9 只 消费第10 只 消费第8 只 消费第11 只 消费第7 只 消费第6 只 消费第5 只 消费第4 只 消费第3 只 消费第2 只 消费第1 只 消费第0 只 生产第11 只 生产第12 只 生产第13 只 生产第14 只 消费第14 只 消费第13 只 消费第12 只