多线程总结:
1.多线程的实现
方式1 : 使用一个继承了 Tread 类并重写其run方法的自定义类来实现
MyThread myThread = new MyThread ( ) ;
启动线程中的run方法:
myThread. start ( ) ;
自定义类:
class MyThread extends Thread {
@Override
public void run ( ) {
System . out. println ( "这是一个run方法" ) ;
}
}
方式2 : 使用一个实现了 Runnable 接口并重写其run方法的自定义类来实现
创建实现类对象:
RunnableThread runnableThread = new RunnableThread ( ) ;
将此对象作为参数传递到Thread 类的构造器中,创建Thread 类的对象通过Thread 类的对象调用start ( )
new Thread ( runnableThread, "线程" ) . start ( ) ;
自定义类:
static class RunnableThread implements Runnable {
int Num = 100 ;
@Override
public void run ( ) {
System . out. println ( "这是一个run方法" ) ;
}
}
相较于方式1 的优点:
该方式构建线程时, 所构建的多个线程会共用一个Runnable 接口的子实现类对象, 若该类中定义有变量, 这样就可以实现这些进程共享同一个变量
方式3 : 使用Callable 方式实现多线程
首先创建一个线程池对象
ExecutorService executorService = Executors . newFixedThreadPool ( ) ;
在submit函数中传递一个Callable 的匿名内部类作为传递参数;其中重写的call方法相当于run方法,并且还需要一个返回值
executorService. submit ( new Callable < Object > ( ) {
@Override
public Object call ( ) throws Exception {
System . out. println ( "这是一个call方法" ) ;
return null ;
}
} ) ;
方式4 : 使用匿名内部类的方式实现多线程
new Thread ( ) {
@Override
public void run ( ) {
System . out. println ( "这是一个run方法" ) ;
}
} . start ( ) ;
Runnable 的匿名内部类作为参数传递到Thread 的构造方法中实现对start ( ) 的调用
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
System . out. println ( "这是一个run方法" ) ;
}
} ) . start ( ) ;
2.获取线程信息、自定义线程名称
获取线程信息:
Thread thread = Thread . currentThread ( ) ;
System . out. println ( "当前线程名称:" + thread. getName ( ) ) ;
System . out. println ( "当前线程ID:" + thread. getId ( ) ) ;
System . out. println ( "当前线程状态:" + thread. getState ( ) ) ;
System . out. println ( "当前线程优先权:" + thread. getPriority ( ) ) ;
自定义线程名称:
首先使用匿名类通过构造器传入自定义的线程名称
new ThreadName ( "李玉龙" ) . start ( ) ;
static class ThreadName extends Thread {
public ThreadName ( String name) {
super ( name) ;
}
@Override
public void run ( ) {
System . out. println ( "这是一个run方法" ) ;
}
}
3.设置线程优先权
注:
1. 优先级设置时需要在1 - 10
2. 值越大优先级越高
3. 线程的执行具有一定的随机性,优先权高的线程不一定先执行,优先权高只表明线程获取到CPU 的执行权的可能性更高
PriorityThread thread1 = new PriorityThread ( "张三" ) ;
thread1. setPriority ( 1 ) ;
PriorityThread thread2 = new PriorityThread ( "李四" ) ;
thread2. setPriority ( 2 ) ;
static class PriorityThread extends Thread {
public PriorityThread ( String name) {
super ( name) ;
}
@Override
public void run ( ) {
for ( int i = 0 ; i < 10 ; i++ ) {
System . out. println ( "当前线程名称:" + this . getName ( ) ) ;
System . out. println ( "当前线程优先权:" + this . getPriority ( ) ) ;
}
}
}
4.线程控制
控制方式:
① sleep 可以使当前的线程处于睡眠状态(具有倒计时的阻塞状态)
sleep ( 1000 ) = > 每次执行当前线程睡眠1 秒
sleep ( long millis, int nanos) = > 按毫秒+ 纳秒方式睡眠
try {
Thread . sleep ( 1000 ) ;
} catch ( InterruptedException e) {
throw new RuntimeException ( e) ;
}
② join 当使用该方法时,其他线程必须等待当前线程执行完成才能继续执行
ControlThread thread1 = new ControlThread ( "李白" ) ;
thread1. start ( ) ;
thread1. join ( ) ;
③ yield 礼让线程, 让当前线程退出CPU 的执行权, 使得所有线程重新争夺CPU 资源
yield ( ) ;
④ setDaemon 设置当前线程为后台守护线程,只要当前存在任何一个非守护线程没有结束,守护线程就必须工作;只有当最后一个非守护线程结束时,守护线程才会随着一同结束工作。
DaemonThread thread = new DaemonThread ( "张三" ) ;
thread. setDaemon ( true ) ;
thread. start ( ) ;
⑤ 中断线程
public final void stop ( ) 强制停止 = > 该方法已经过时了
public void interrupt ( ) 非强制执行, 在当前线程在本次CPU 执行时间片断执行完成后, 再进行关闭操作
会有异常提示信息
if ( "邱六" . equals ( this . getName ( ) ) && i == 3 ) {
this . stop ( ) ;
this . interrupt ( ) ;
}
5.对共享变量加锁
对于多个线程使用同一个变量所造成的线程不安全的问题,我们可以通过对共享变量上锁来进行解决
1. 对当前对象进行上锁
sellRunnable对象是 全局唯一的 ,并且其中的变量ticksNum也是唯一的;因此可以对当前对象进行上锁
SellRunnable sellRunnable = new SellRunnable ( ) ;
new Thread ( sellRunnable, "售票员1" ) . start ( ) ;
new Thread ( sellRunnable, "售票员2" ) . start ( ) ;
static class SellRunnable implements Runnable {
int ticksNum = 100 ;
@Override
public void run ( ) {
while ( true ) {
synchronized ( this ) {
对共享变量的操作
}
}
}
}
2. 对类进行上锁,类中的变量为静态变量
new SynchronizedClazz ( "销售员1" ) . start ( ) ;
new SynchronizedClazz ( "销售员2" ) . start ( ) ;
static class SynchronizedClazz extends Thread {
public SynchronizedClazz ( String name) {
super ( name) ;
}
@Override
public void run ( ) {
synchronized ( TicksNumClazz . class ) {
if ( TicksNumClazz . getNum ( ) > 0 )
对共享变量进行操作
}
}
}
static class TicksNumClazz {
static int num = 100 ;
public static void sellTick ( ) {
num -= 1 ;
}
public static int getNum ( ) {
return num;
}
}
3. 对类进行上锁,类中的变量不为静态变量
2 中的写法,使用的是静态变量
在有些场合下,不是很方便
TicksNum ticksNum = new TicksNum ( ) ;
TicksNumObject ticksNumObject = new TicksNumObject ( ticksNum) ;
new SynchronizedClazz ( "销售员1" , ticksNumObject) . start ( ) ;
new SynchronizedClazz ( "销售员2" , ticksNumObject) . start ( ) ;
static class SynchronizedClazz extends Thread {
TicksNumObject ticksNumObject;
public SynchronizedClazz ( String name, TicksNumObject ticksNumObject) {
super ( name) ;
this . ticksNumObject = ticksNumObject;
}
@Override
public void run ( ) {
while ( true ) {
synchronized ( TicksNumObject . class ) {
if ( ticksNumObject. ticksNum. getNum ( ) > 0 )
对共享变量进行操作
}
}
}
}
static class TicksNumObject {
TicksNum ticksNum;
public TicksNumObject ( TicksNum ticksNum) {
this . ticksNum = ticksNum;
}
}
static class TicksNum {
int num = 100 ;
public void sellTick ( ) {
num -= 1 ;
}
public int getNum ( ) {
return num;
}
}
6.线程同步
① synchronized 也可以对当前成员方法进行加锁,加锁的是当前对象
public synchronized void sell ( )
② synchronized 也可以对当前静态方法进行加锁,加锁的是当前方法所属的类
public static synchronized void sell ( )
③ notify 作用是从当前对象被锁定的线程中唤醒一个线程; notifyAll的作用是幻想所有线程
④ wait 作用是让当前线程进入阻塞状态,并释放并释放对象的锁。如果要被唤醒,那么必须有一个线程使用 notify
⑤ notify和wait必须在synchronized 修饰的代码块或者方法中才能存在
⑥ notify和wait是属于顶级父类Object 中的方法
⑦ notify和wait 调用的对象,必须是被加锁的
try {
tickNum. notify ( ) ;
tickNum. wait ( ) ;
} catch ( InterruptedException e) {
throw new RuntimeException ( e) ;
}
7. Lock锁
Lock 锁,可以得到和 synchronized 一样的效果,即实现原子性、有序性和可见性。
相较于synchronized ,Lock 锁可手动获取锁和释放锁、可中断的获取锁、超时获取锁。
具体实现:
lock. lock ( ) ;
if ( tickNum > 0 ) {
sell ( ) ;
} else {
break ;
}
lock. unlock ( ) ;
8. 线程组
ThreadGroup threadGroup1 = new ThreadGroup ( "帅哥组" ) ;
MyThread thread3 = new MyThread ( threadGroup1, "雍正" ) ;
MyThread thread4 = new MyThread ( threadGroup1, "康熙" ) ;
thread3. start ( ) ;
thread4. start ( ) ;
static class MyThread extends Thread {
public MyThread ( ThreadGroup group, String name) {
super ( group, name) ;
}
@Override
public void run ( ) {
for ( int i = 0 ; i < 100 ; i++ ) {
if ( i >= 10 && this . getThreadGroup ( ) . getName ( ) == "美女组" ) {
this . getThreadGroup ( ) . stop ( ) ;
}
System . out. println ( this . getThreadGroup ( ) . getName ( ) + "线程名称:" + this . getName ( ) + "正在打印第" + i + "个值" ) ;
}
}
}
9. 线程池
ExecutorService executorService1 = Executors . newCachedThreadPool ( ) ;
executorService1. submit ( new MyThreadRunnable ( ) ) ;
executorService1. shutdownNow ( ) ;
executorService1. shutdown ( ) ;
ExecutorService executorService = Executors . newFixedThreadPool ( 3 ) ;
executorService. submit ( new MyThreadRunnable ( ) ) ;
executorService. submit ( new MyThreadRunnable ( ) ) ;
executorService. submit ( new MyThreadRunnable ( ) ) ;
executorService. submit ( new MyThreadRunnable ( ) ) ;
执行结果:
10. Timer的任务调度
我们可以给定一个执行的策略,来操控任务的执行,比如每5 秒执行一次
具体实现:
Timer timer = new Timer ( ) ;
timer. schedule ( new MyTask ( ) , 5000 ) ;
timer. schedule ( new MyTask ( ) , 1000 , 4000 ) ;
static class MyTask extends TimerTask {
@Override
public void run ( ) {
System . out. println ( "定时炸弹被引爆,pong...." ) ;
}
}