Java多线程基础学习
并发
并发是什么呢?
一个CPU对应了多个进程[程序:QQ,wx]
并行
并行是?
多个CPU对应多个进程,例如CPU1=》QQ ,CPU2=》WX
进程
开启了一个软件,就是启动一个进程。
例如:开启了QQ,就是启动了一个进程。
线程
开启了一个软件,软件里面还可以开启其他软件或者其他功能。
例如:开启了QQ,打开QQ宠物,开启了一个线程。
如何创建线程
继承Thread类
class Thread01 extends Therad { //这里必须去重写父类的run方法。 //run方法里面写的就是线程的动作。 public void run(){ } } public class D{ public static void main(String args[]){ //如何去调用这个线程,是创建继线程类的对象 //然后去调用,start方法启动线程。 Thread01 t0 = new Thread01; t0.start(); } }
实现Runnable接口
class Thread02 implements Runnable { //这里必须去实现接口的run方法,我们让这个线程去干嘛? //run方法里面写的就是线程的动作。 public void run(){ } } public class D{ public static void main(String args[]){ //如何去调用这个线程,是创建继线程类的对象 //然后去调用,start方法启动线程。 Thread02 t0 = new Thread02; //注意:Runnable接口里面只有一个run方法,没有其他方法 //这里调用start方法肯定不行 //t0.start(); //这里我们创建一个线程类,这个类的构造器里面是可以传入一个线程的 //这样我们就可以调用start方法了 new Thread(t0).start(); } }
为什么要调用start方法呢?不是调用run方法的呢?
他的start方法里面调用了一个叫start0()的方法
start0方法:private native void start0();
这个是一个 native显示的方法,底层是c或者其他语音写的jvm去调用的。
就在这里,调用run方法什么时候调用的呢?要看jvm的了。
线程里面的方法
public class Thread04 { public static void main(String[] args) throws InterruptedException { Dog dog = new Dog(); Thread thread = new Thread(dog); thread.start(); // 线程睡眠多少毫秒 Thread.sleep(100); // 设置线程的优先级的,有固定的几个值输入错误会爆异常的 /** * The minimum【最低的】 priority that a thread can have. * public static final int MIN_PRIORITY = 1; */ /** * The default【默认的】 priority that is assigned to a thread. * public static final int NORM_PRIORITY = 5; */ /** * The maximum【最高的】 priority that a thread can have. * public static final int MAX_PRIORITY = 10; */ thread.setPriority(1); //设置线程的名字 thread.setName("我的名字1"); // 设置成为守护线程:简单理解就是当其他线程全部结束的时候,这个守护线程就会自动结束 // 守护线程:①当其他线程运行结束了,他就自动结束了 // ②必须放在启动之前,就是start方法的前面 // ③当其他线程全部结束的时候,他会自动结束不过之前会自己调用一次 // 例如:dog线程跑15次,cat线程跑10次。我们要cat线程跑10次的时候,我们的dog线程就结束了 // 我们只要把dog设置成为守护线程即可的,当cat线程结束了dog线程就结束了 thread.setDaemon(true); thread.join(); // 这个是等待 // 简单理解就是:一个线程正在运行,突然调用另一个线程的join方法之后 // 正在运行的线程要停下来,等join的线程运行完成之后才能在运行自己的线程 } } class Dog implements Runnable{ @Override public void run() { } } class Cat implements Runnable{ @Override public void run() { } }
setPriority(int num);
设置优先级别的,有固定的优先级别:1最小 5默认 10最大
setDaemon(true);
设置是否是守护线程
守护线程就是其他线程结束了,他就自动结束了
gc就是一个守护线程
线程的生命周期
线程有6个状态[状态就是目前这个线程正在干什么]
new 刚刚创建的状态
runnable JVM中正在运行的线程,运行状态
blocked 被阻塞了正在等待监听器锁定这个线程的状态,阻塞状态
waiting 等待另一个线程执行某一个片段的那个线程,等待状态
time_waiting 正在等待另一个线程执行动作达到指定等待时间的线程处于这个状态。
terminated 死亡状态,线程被销毁的时候
创建,运行,等待,正在等待,死亡。
创建 New
在调用start方法之前,就是new一个线程出来了
运行 Runnable 分两种
调用start时候启动的
①就绪状态 ready
②运行状态 running
阻塞状态 Blocked
一直在等待资源的回复,这种线程或者
想要调用其他线程的独有的资源
线程在阻塞状态,是不占CPU的
等待状态 Waiting
线程执行了一些方法的时候,wait join这些方法的时候这个线程处于等待状态
定时等待状态 Timed_Waiting
和waiting差不多,只不过他不会一直等待下去。他是有一个时间限制的,
销毁 Terminated
线程终止了
线程生命周期图解
Synchronized关键字/互斥锁
车票出售系统
public class ChePiao { public static void main(String[] args) { Cku cku = new Cku(); new Thread(cku).start(); new Thread(cku).start(); new Thread(cku).start(); } } class Cku implements Runnable{ int num = 100; @Override public void run() { while (true){ if (num > 0){ System.out.println(Thread.currentThread().getName() + " 卖了 =" + num); num--; } } } }
这里的num,应该是卖了一个就少了一个。但是你会发现,num在不同线程里面数字既然有相同的,感情上面卖票不止100张啊,还多了。怎么办吧
解决一个问题:在对于num-- 的时候我们只能让一个线程去访问
等那个线程操作资源结束了,后面的才能去访问!
Synchronized
这个关键字的,明显需求就是车票销售系统
一共10张票,5个窗口去卖票。会不会出现同时5个窗口都在卖最后一张票导致票出现负数了
有一个概念我一直搞错了
我打出来的是,实体的票数
其实我们要打印的是窗口出售的票数的
package com.hu.therad_.dome01; //车票出售系统 public class ChePiao { public static void main(String[] args) { Wind wind = new Wind(); new Thread(wind).start(); new Thread(wind).start(); } } class Wind implements Runnable{ int nums = 10; int i = 0; @Override public void run() { while (true){ synchronized (this){ if (nums <= 0){ System.out.println("没有票了"); break; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } nums--; i++; System.out.println(Thread.currentThread().getName() + " 已经卖出了: "+ i + " 剩余票数: " + nums); } } } }
如何解决这个事情,加关键字 synchronized 关键字
- 一个只能同时被一个线程获取,其他线程只能等待
- 每一个对象(new)都有对应自己的一个,不同的对象是互不影响的。
- synchronized修饰static方法或者类的时候就是这个对象
- synchronized修饰的方法,抛出异常之后会释放
看懂不为什么要叫,是关门的时候的动作吗?
synchronized怎么用
对象
synchronized(对象/this){ 代码块 } public synchronized void run(){} 修饰方法的时候默认的对象是this