进程:正在进行的程序。
线程:指的是 进程当中某一个子任务或者子功能。
线程作用
并发 | 并行 |
---|---|
并发是指两个或多个事件在同一时间间隔发生 | 并行是指两个或者多个事件在同一时刻发生 |
并发是在同一实体上的多个事件 | 并行是在不同实体上的多个事件 |
发是在多台处理器上同时处理多个任务 | 并行是在一台处理器上“同时”处理多个任务 |
更多内容参考: https://www.jianshu.com/p/cbf9588b2afb
package com.qianfeng.thread;
public class MyThread extends Thread{
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
package com.qianfeng.thread;
public class MyThread1 implements Runnable{
public void run() {
for (char i = 'a'; i < 'z'; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.start();
t2.start();
@Test
public void test() {
MyThread1 m1=new MyThread1();
Thread t1=new Thread(m1);
Thread t2=new Thread(m1);
t1.start();
t2.start();
}
初始状态----->相当于是新创建了线程对象 Thread t1=new Thread(task);
就绪状态------>调用了线程类的start方法。 t1.start();注:cpu还没有分配时间片
运行状态------>cpu分配了时间片给当前线程 run方法被执行 。 run()…
结束状态------>当线程 跑完run方法之后。
方法 | 含义 |
---|---|
Thread.currentThread().getName(); | 获得当前线程的名称 |
MyTread t1=new Mythread(); t1.setName(“线程一”); |
给某个线程设置名称 |
t1.isDaemon(); | 判断当前线程是否是守护线程(类型于gc) |
t1.getPriority(); | 获得当前线程的优先级 |
t1.setPriority(); | 设置当前线程的优先级 |
Thread.sleep(long millis) | 当前的线程 等待 一个毫秒值 |
t1.join(); | 在当前的线程中 强势加入另一个线程 需要使加入进来的这线程 先运行完 我们的当前线程才可以继续运行。 |
Thread.currentThread().yield(); | 当前线程让出cpu时间片 重新使当前线程处于就绪状态 , 再次获得时间片时,继续执行礼让后的代码 |
当前的线程 等待 一个毫秒值
Thread.sleep(long millis)
在当前的线程中 强势加入另一个线程
public static void main(String[] args) throws InterruptedException {
MyThread t1=new MyThread();
t1.start();
MyThread t2=new MyThread();
t2.start();
for (int i = 0; i < 1000; i++) {
if(i==50){
t1.join();
}
System.out.println("main:"+i);
}
}
线程礼让方法 yield();
@Test
public void testYield(){
new Thread(new Runnable() {
@Override
public void run() {
Thread.currentThread().yield();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
Thread.currentThread().yield();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}).start();
}
JDK5之后,把线程的状态归纳为6个状态,其中就绪状态和运行状态都属性 启动状态。
线程状态:7种(jdk1.5之前)
初始状态:new Thread();
就绪状态:调用start方法
运行状态:获取时间片
有限期等待:调用Thread.sleep(毫秒值),等待结束之后,进入就绪状态,等待时间片的分配
无限期等待:在当前线程中,调用其它线程的join方法,等其它线程执行完毕之后,当前线程进入就绪状态,等待时间片的分配
阻塞状态:当线程去获取对象的锁对象时,如果此时对象上没有锁标记,则该线程就会阻塞。
结束状态:线程执行完毕
这些状态定义在枚举Thread.State中:
产生的原因:
多个密不可分的操作称为“原子操作”,即不可再分!
在上述的例子中,两个线程都可以访问的那个数组,就是临界资源,判断是否为null位和将值存入到指定的位置,就是一个“原子操作”
临界资源: 多个线程同时操作1个对象,这个对象就是临界资源(共享资源)
方式1:同步代码块
//临界资源最好为类对象(例this),如果换成非引用对象(eg:Integer对象),有时会失效
synchronized ( 临界资源 ) {
// 原子操作
}
方式2:同步方法
同步方法:临界资源是this
public synchronized void xxx() {
// 原子操作
}
wait() ,notify(), notifyAll()都源自Object–所有的类都有这三个方法
wait()
notify();
notifyAll();
notify和notifyAll() 注意点
package com.qianfeng.Thread;
import java.util.*;
public class KFC {//实体列--KFC
private LinkedList<String> items=new LinkedList<String>();
public synchronized void put() throws InterruptedException {
while(items.size()>=5) {,
this.wait();
}
items.add("汉堡");
System.out.println(Thread.currentThread().getName()+":生产一个汉堡,剩余:"+items.size());
this.notifyAll();
}
public synchronized void get() throws InterruptedException {
while(items.size()==0) {
this.wait();
}
items.remove(0);
System.out.println(Thread.currentThread().getName()+":消费一个汉堡剩余:"+items.size());
this.notifyAll();
}
}
//生产者
package com.qianfeng.Thread;
public class Produce implements Runnable{
private KFC kfc;
public Produce(KFC kfc) {
this.kfc = kfc;
}
@Override
public void run() {
while(true) {
try {
kfc.put();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//消费者
package com.qianfeng.Thread;
public class Consume implements Runnable{
private KFC kfc;
public Consume(KFC kfc) {
this.kfc = kfc;
}
@Override
public void run() {
while(true) {
try {
kfc.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//测试Demo
package com.qianfeng.Thread;
public class Demo {
public static void main(String[] args) {
KFC kfc=new KFC();//创建KFC类对象
Produce p=new Produce(kfc);//创建生产者线程,赋予同一个类属性方法
Consume c=new Consume(kfc);//创建消费者线程,赋予同一个类属性方法
Thread t1=new Thread(p,"生产者1");
Thread t2=new Thread(c,"消费者1");
Thread t3=new Thread(p,"生产者2");
Thread t4=new Thread(c,"消费者2");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
创建线程池–Executor:线程池的顶级接口。
创建案例
// 创建线程的个数需要根据系统规模及内存作为参考
ExecutorService pool1 = Executors.newFixedThreadPool(5);
// 该方式创建的线程池中的线程数是动态维护的:不够则创建,空闲则销毁,不适用于访问量激增的程序。
ExecutorService pool2 = Executors.newCachedThreadPool();
线程池–创建任务,开启任务
接口实现案例–匿名内部类
ExecutorService es = Executors.newCachedThreadPool();//这是一个动态的线程池
//Runnable
es.submit(new Runnable() {//Rannable
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
});
//Callable
Future <T> f =es.submit(new Callable<T>() {//Callable
@Override
public T call()throws Exception {
int sum=0;
for (int i = 0; i < 1000; i++)
sum+=i;
return sum;//决定了了泛型的类型--T :Integer
}
});
//获取值
//f.get()-主线程调用时会等线程真正产生返回值后再去运行
多线程使用synchronized来保持线程之间同步互斥,jdk1.5中加入了Lock对象也能实现同步效果
Re entra nt Lock(rɪ’entrənt)类的使用,ReentrantReadWriteLock类的使用
ReentrantLock 概述
ReentrantLock与synchonized的异同
优势
reentrant 锁意味着什么呢?
简单来说,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放。这模仿了 synchronized 的语义;如果线程进入由线程已经拥有的监控器保护的 synchronized 块,就允许线程继续进行,当线程退出第二个(或者后续) synchronized 块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个 synchronized 块时,才释放锁。
lock与unlock
await(),signal() 线程通信–类似于wait(),notify()/notifyAll()
案例代码–与sychronized+wait()+notify()的一致的代码
package cn.thread.lock.reentrant;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class MyService {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void serviceA() {
try {
//Thread.sleep(100);
lock.lock();// lock是一把锁
code.....
condition.await(); //线程挂起,进入等待状态
System.out.println(Thread.currentThread().getName() + "----Ai=" + i);
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
//condition.signal();在其他的方法中使用该段代码,唤醒被await挂起的servuceA线程
}
}
概述
Lock锁分为公平锁和非公平锁
公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得FIFO。
非公平锁就是一种获取锁的抢占机制,随机获得锁。