进程:进程是程序执行的基本实体(一个软件运行之后就是一个进程)
线程:线程是操作系统能够调度的最小单位,包含在进程中,是进程中的实际运作单位。
多线程可以让程序同时做多件事,已提高效率,
并发:同一时刻,多个指令,在单个CPU上交替执行
并行:同一时刻,多个指令,在多个CPU上同时执行
Thread thread=new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"world");
}
}
};
thread.setName("hello");
thread.start();
public class MyThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"hellp");
}
}
}
/*
* 特点:可以获取到多线程运行的结果
* 1,创建一个类实现Callable接口
* 2,重写call(有返回值,表示多线程运行的结果)
* 3,创建对象,(表示多线程执行的任务)
* 4,创建FutureTask对象(作用管理多线程运行结果)
* 5,创建Thread类对象,并启动
* */
public class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
//求1-100和
int res=0;
for (int i = 0; i < 100; i++) {
res+=i;
}
return res;
}
}
//创建对象
MyThread myThread = new MyThread();
//创建FutureTask对象
FutureTask<Integer> futureTask=new FutureTask<>(myThread);
//创建Thread类对象,并启动
Thread thread=new Thread(futureTask);
//获取到结果
Integer res = futureTask.get();
System.out.println(res);
java中是抢占式调度(是随机的),优先级越高,抢占到线程的概率越大
Thread thread1=new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
},"飞机");
Thread thread2=new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
},"坦克");
//输出可以看到默认为5
System.out.println(thread1.getPriority());
System.out.println(thread2.getPriority());
System.out.println(Thread.currentThread().getPriority());
//优先级为1-10
thread1.setPriority(1);
thread2.setPriority(10);
thread1.start();
thread2.start();
//当其他线程结束时,守护线程也会结束
Thread thread1=new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
},"女神");
Thread thread2=new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
},"坦克");
thread2.setDaemon(true);
thread1.start();
thread2.start();
//出让当前Cpu的执行权
Thread.yield();
//下面代码,thread2是在线程1启动之前,但是thread1.join();表示插入到thread2线程之前执行
Thread thread1=new Thread(()->{
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
},"女神");
Thread thread2=new Thread(()->{
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+i);
Thread.yield();
}
},"坦克");
thread2.start();
thread1.start();
同步代码块:把操作共享数据的代码锁起来
特点:
//格式
synchronized(锁){
//操作共享数据的代码
}
//买票问题
while (true){
synchronized(MyThread1.class){
if ( num<100){
num++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"在卖第"+num+"张票");
}else {
break;
}
}
}
同步方法:把synchronized关键字加到方法上
特点
//格式
修饰符 synchronized 返回值 方法名(参数)
//如果不会写,可以先写同步代码块 ,然后ctrl+alt+m可以抽取成一个方法
public class MyThread1 implements Runnable {
static int num=0;
@Override
public void run() {
while (true){
if (extracted()) break;
}
}
private synchronized boolean extracted() {
if (num<100){
num++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"在卖第"+num+"张票");
}else {
return true;
}
return false;
}
}
Runnable myThread1 = new MyThread1() {
};
Thread thread =new Thread(myThread1,"窗口1");
Thread thread2 =new Thread(myThread1,"窗口2");
Thread thread3 =new Thread(myThread1,"窗口3");
thread.start();
thread2.start();
thread3.start();
为了更加清晰的了解如何加锁和释放锁,jdk1.5提供了一个新的锁对象Lock
lock()获得锁
unlock()释放锁
手动上锁,手动释放锁
Lock接口不能直接实例化,采用他的实现类ReentrantLock来实例化
//这里要注意的是 在一个线程结束的时候一定要执行lock.unlock();,要不然其他的线程都结束不了
public class MyThread1 extends Thread{
static int num=0;
static Lock lock=new ReentrantLock();
public MyThread1(String name) {
super(name);
}
@Override
public void run() {
while (true){
lock.lock();
try {
if ( num<100){
num++;
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+"在卖第"+num+"张票");
}else {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
相当于锁嵌套,a线程拿到a资源之后要去拿b资源,b线程拿了b资源要去拿a资源,两个线程就死锁了
常见方法
void wait()//当前线程等待,直到被唤醒
void notify()//随机唤醒单个线程
void notifyAll()//唤醒所有线程
//实现
public class Desk {
//控制生产者和消费者的执行
//是否有面条 0没有 1有
public static int foodFlag=0;
//总个数
public static int count=10;
static Object lock=new Object();
}
public class Cook extends Thread{
@Override
public void run() {
while (true){
synchronized(Desk.lock){
if (Desk.count==0){
break;
}else {
//判断桌子上是否有食物
//如果有,就等待
if(Desk.foodFlag==1){
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
//没有没有。制作
System.out.println("厨师做了一碗");
//修改做字状态
Desk.foodFlag=1;
//等待消费者开吃
Desk.lock.notifyAll();
}
}
}
}
}
}
public class Foodie extends Thread{
@Override
public void run() {
/*循环
* 同步代码块
* 判断共享数据是否到了末尾(到了)
* 没有到末尾*/
while (true){
synchronized(Desk.lock){
if (Desk.count==0){
break;
}else {
//判断桌子上是否有食物
//没有,等待
if (Desk.foodFlag==0){
try {
//让当前线程和锁进行绑定,唤醒的时候也是通过这个对象
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
//有,消费
//吃的总是-1
Desk.count--;
System.out.println("开始消费,还能吃"+Desk.count);
//消费完成,唤醒厨师
Desk.lock.notifyAll();
//修改桌子状态
Desk.foodFlag=0;
}
}
}
}
}
}
//利用阻塞队列实现
//需要注意:生产者和消费者需要使用同一个阻塞队列
//创建阻塞队列对象
ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(1);
//创建线程对象,并且把阻塞队列传过去
Cook cook=new Cook(queue);
Foodie foodie = new Foodie(queue);
cook.start();
foodie.start();
public class Cook extends Thread{
ArrayBlockingQueue<String> queue;
public Cook(ArrayBlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
while (true){
try {
queue.put("面条");
System.out.println("做了一份");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Foodie extends Thread{
ArrayBlockingQueue<String> queue;
public Foodie(ArrayBlockingQueue<String> queue){
this.queue=queue;
}
@Override
public void run() {
/*循环
* 同步代码块
* 判断共享数据是否到了末尾(到了)
* 没有到末尾*/
while (true){
try {
String take = queue.take();
System.out.println(take);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
但是实际上JAVA中定义的只有这六种
新建:NEW
就绪状态:RUNABLE
阻塞状态:BLOCKED
无限期等待:WAITING
计时等待:TIMED_WAITING
结束状态:TERMINATED
需要线程的时候就去创建,用完就消失了
核心原理
代码实现
//1,创建线程池
ExecutorService pool1 = Executors.newCachedThreadPool();
//有上限的线程池
ExecutorService pool2 = Executors.newFixedThreadPool(3);
//2,提交任务
pool1.submit(new MyThread1());
//3,所有任务执行完毕,关闭线程池
pool1.shutdown();
什么时候创建临时线程,核心线程都没有空闲,且排队的任务排满。(所以不一定先提交的就会先执行)
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
3,//核心线程数量,不能小于0
6,//最大核心线程数,不能小于0,>=核心线程数
60,//空闲线程最大存活时间
TimeUnit.SECONDS,//时间单位
new ArrayBlockingQueue<>(3),//任务队列
Executors.defaultThreadFactory(),//创建线程工厂
new ThreadPoolExecutor.AbortPolicy()//任务拒绝方式
);
最大线程数应该是CPU核心的两倍比较合适