JavaDay16-多线程(一)
一、多线程
1、并发、并行
- 并发:同一时刻 多个指令 单个CPU上交替执行
- 并行:同一时刻 多个指令 多个CPU上同时执行多
2、多任务、多线程
- 多任务:很多任务一项一项的处理,一次一件
- 多线程:同时处理多个线程,一次多件
3、程序、进程process、线程thread
- 程序:就是写好的代码,是静态的
- 进程:是指程序执行一次,是动态的。是系统资源分配的单位。一个进程可以有多个线程,因为一个程序中可以有多个方法。
- 线程:是CPU执行的最小单位,一个进程可以有多个线程,一个main方法就是一个线程。
4、核心概念
- 线程是独立的执行路径
- 程序运行时,即使没有创建线程,后台也会有多个线程,如主线程(main)、gc线程
- 如果一个进程中开辟了多个线程,那么线程的运行顺序是由调度器安排调度的,不能人为干预
- 资源抢夺:对同一份资源进行操作,需要加入并发控制
- 线程会带来额外的开销,如CPU调度、并发控制开销
- 线程在自己的工作内存交互,如果内存控制不当会造成数据不一致。
二、创建线程的三种方法
1、继承Thread类
//多线程的第一种实现方式
/*
继承Thread类、重写run方法;
创建子类对象、调用start方法。
*/
public class ThreadDemo01 {
public static void main(String[] args) {
MyRun run1 = new MyRun();
MyRun run2 = new MyRun();
MyRun run3 = new MyRun();
run1.setName("1");
run2.setName("2");
run3.setName("3");
run1.start();
run2.start();
run3.start();
}
}
//Demo01的MyRun
public class MyRun extends Thread{
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println(getName()+"多线程");
}
}
}
2、实现Runnable接口
//多线程的第二种实现方式
/*
实现runnable接口,重写run方法;
创建 实现了runnable接口 的对象;
创建Thread对象,调用start方法。
*/
public class ThreadDemo02 {
public static void main(String[] args) {
MyRun run = new MyRun();
Thread thread1 = new Thread(run);
Thread thread2 = new Thread(run);
Thread thread3 = new Thread(run);
thread1.setName("1");
thread2.setName("2");
thread3.setName("3");
thread1.start();
thread2.start();
thread3.start();
}
}
//Demo02的MyRun
public class MyRun implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"多线程");
}
}
}
3、Callable接口+Future接口
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//多线程的第三种实现方式
/*
1、创建多线程类,实现callable接口(泛型接口),重写call方法
2、创建多线程对象
3、创建FutureTask对象,管理多线程程序的运行结果
4、创建Tread对象,调用start方法
5、通过FutureTask对象,调用get方法,获取多线程程序的运行结果
*/
public class ThreadDemo03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyRun myRun = new MyRun();
//管理多线程程序运行的结果 泛型与多线程程序保持一致
FutureTask<Integer> future = new FutureTask<>(myRun);
Thread thread = new Thread(future);
thread.start();
Integer sum = future.get();
System.out.println(sum);
}
}
import java.util.concurrent.Callable;
//Demo03的MyRun
public class MyRun implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i < 100; i++) {
sum +=i;
}
return sum;
}
}
三、同步代码块、同步方法
1、同步代码块(卖票的例子)
//多个线程操作一个数据--卖票
//同步代码块
/*
问题:
1、不同对象共享数据
2、出现相同的票--cpu资源在运行过程中随时有可能被其他线程抢走
3、出现超出范围的票
解决:
同步代码块-把操作共享数据的代码锁起来
特点:
1、锁默认打开,有一个线程进去了,锁自动关闭
2、里面的代码全部执行完毕,线程出来,锁自动打开
*/
public class ThreadDemo04 {
public static void main(String[] args) {
SoldDemo soldDemo1 = new SoldDemo();
SoldDemo soldDemo2 = new SoldDemo();
SoldDemo soldDemo3 = new SoldDemo();
soldDemo1.start();
soldDemo2.start();
soldDemo3.start();
}
}
public class SoldDemo extends Thread{
private static int ticket;//static表示这个类的所有对象都共享ticket数据
//static关键字保证对象必须唯一
static Object obj=new Object();
@Override
public void run() {
while (true){
//同步代码块
synchronized (obj){//也可以是SoldDemo.class(保证对象这个参数是唯一的)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (ticket<100){
System.out.println(Thread.currentThread().getName()+"第"+ticket+"张票");
ticket++;
}else {
break;
}
}
}
}
}
2、同步方法(卖票的例子)
//卖票
//同步方法
public class ThreadDemo05 {
public static void main(String[] args) {
MyRunnableDemo demo = new MyRunnableDemo();
Thread thread1 = new Thread(demo);
Thread thread2 = new Thread(demo);
Thread thread3 = new Thread(demo);
thread1.start();
thread2.start();
thread3.start();
}
}
public class MyRunnableDemo implements Runnable{
int ticket;//不需要加static,因为只会创建一个MyRunnableDemo对象
@Override
public void run() {
while (true){
if (method()) break;
}
}
//ctrl alt m--自动生成方法
private synchronized boolean method() {
if (ticket<100){
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
ticket++;
}else {
return true;
}
return false;
}
}
四、多线程中常用的成员方法
1、public final String getName()
- 获取线程的名字
2、public final synchronized void setName(String name)
- final-不能被子类重写;
- synchronized-代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行
- 细节:
- 如果没有给线程设置名字,线程也是有默认名字的。格式:Thread-X(X是序号,从0开始)
- 如果需要给线程设置名字,可以通过setName方法,也可以通过构造方法
3、public static native Thread currentThread()
- static:表示可以直接用类名调用,不需要实例化对象;通过native修饰的方法可以调用本地程序库或操作系统的API,以实现一些Java本身无法实现的功能
4、public static void sleep(long time)
- 细节:哪条线程执行到这个方法,就会在此停留多长时间
5、public final int getPriority()
- 获取线程优先级
6、public final void setPriority(int newPriority)
- 设置线程优先级
- 细节:
- 线程的默认优先级是5
- 最高优先级为10
- 最低优先级为1
7、public final void setDaemon(boolean on)
- 设置守护线程
- 细节:
- 当非守护线程执行完毕后,守护线程也会陆续结束,不会执行完
五、线程的生命周期
1、创建线程对象
2、就绪--抢CPU--有执行资格、没有执行权
3、运行--运行代码--有执行资格、有执行权
4、死亡--垃圾(运行完)
5、阻塞--等待--没有执行资格、没有执行权(sleep()或者其他阻塞方法)

浙公网安备 33010602011771号