多线程
线程:单一的顺序执行流程就是一个线程,顺序执行:代码一句一句的先后执行。
多线程:多个线程并发执行。线程之间的代码是快速被CPU切换执行的,造成一种感官上"同时"执行的效果。
线程的创建方式
-
继承Thread,重写run方法,在run方法中定义线程要执行的任务
优点:
- 结构简单,便于匿名内部类创建
缺点:
- 继承冲突:由于java单继承,导致如果继承了线程就无法再继承其他类去复用方法
- 耦合问题:线程与任务耦合在一起,不利于线程的重用。
-
实现Runnable接口单独定义线程任务
优点:
- 犹豫是实现接口,没有继承冲突问题
- 线程与任务没有耦合关系,便于线程的重用
缺点:
- 创建复杂一些(其实也不能算缺点)
线程Thread类的常用方法
void run():线程本身有run方法,可以在第一种创建线程时重写该方法来定义线程任务。
void start():启动线程的方法。调用后线程被纳入到线程调度器中统一管理,并处于RUNNABLE状态,等待分配时间片开始并发运行。
注:线程第一次获取时间片开始执行时会自动执行run方法。
**启动线程一定是调用start方法,而不能调用run方法!**
String getName():获取线程名字
long getId():获取线程唯一标识
int getPriority():获取线程优先级,对应的是整数1-10
boolean isAlive():线程是否还活着
boolean isDaemon():是否为守护线程
boolean isInterrupted():是否被中断了
void setPriority(int priority):设置线程优先级,参数可以传入整数1-10。1为最低优先级,5为默认优先级,10为最高优先级
优先级越高的线程获取时间片的次数越多。可以使用Thread的常量MIN_PRIORITY,NORM_PRIORITY,MAX_PRIORITY。
他们分别表示最低,默认,最高优先级
static void sleep(long ms):静态方法sleep可以让运行该方法的线程阻塞参数ms指定的毫秒。
static Thread currentThread():获取运行该方法的线程。
void setDaemon(boolean on):设置线程是否为守护线程,当参数为true时当前线程被设置为守护线程。该操作必须在线程启动前进行
守护线程与普通线程的区别主要体现在当java进程中所有的普通线程都结束时进程会结束,在结束前会杀死所有还在运行的守护线程。
重点:多线程并发安全问题
-
什么是多线程并发安全问题:
当多个线程并发操作同一临界资源,由于线程切换时机不确定,导致执行顺序出现混乱。
解决办法:
将并发操作改为同步操作就可有效的解决多线程并发安全问题
-
同步与异步的概念:同步和异步都是说的多线程的执行方式。
多线程各自执行各自的就是异步执行,而多线程执行出现了先后顺序进行就是同步执行
-
synchronized的两种用法
xxxxxxxxxx package thread;/** * 守护线程 * 线程提供了一个方法: * void setDaemon(boolean on) * 如果参数为true,则会将当前线程设置为守护线程。 * * 守护线程与普通的用户线程(线程创建出来时默认就是用户线程)的区别在于进程结束 * * 进程结束: * 当一个JAVA进程中所有的用户线程都结束时,进程就会结束,此时会强制杀死所有还在运行 * 的守护线程。 * * GC就是运行在一条守护线程上的。 */public class DaemonThreadDemo { public static void main(String[] args) { Thread rose = new Thread(“rose”){ public void run(){ for(int i=0;i<5;i++){ System.out.println(getName()+“:let me go !!!”); try { Thread.sleep(1000); } catch (InterruptedException e) { } } System.out.println(getName()+“:啊啊啊啊啊AAAAAAaaaaa…”); System.out.println(“噗通!”); } }; Thread jack = new Thread(“jack”){ public void run(){ while(true){ System.out.println(getName()+“:you jump!i jump!”); try { Thread.sleep(1000); } catch (InterruptedException e) { } } } }; rose.start(); jack.setDaemon(true);//设置守护线程必须在线程启动前进行 jack.start(); }}java
2.同步块,推荐使用。同步块可以更准确的控制需要同步执行的代码片段。
有效的缩小同步范围可以在保证并发安全的前提下提高并发效率
-
同步监视器对象的选取:
对于同步的成员方法而言,同步监视器对象不可指定,只能是this
对于同步的静态方法而言,同步监视器对象也不可指定,只能是类对象
对于同步块而言,需要自行指定同步监视器对象,选取原则:
1.必须是引用类型
2.多个需要同步执行该同步块的线程看到的该对象必须是同一个
-
互斥性
当使用多个synchronized修饰了多个代码片段,并且指定的同步监视器都是同一个对象时,这些代码片段就是互斥的,多个线程不能同时在这些代码片段上执行。