1、多线程
1、线程与进程
1、进程
是指一个内存运行中的应用程序,每个进程都有一个独立的内存空间
2、线程
是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程至少有一个线程,
线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程
2、线程调度
java:抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,
CPU 使用抢占式调度模式在多个线程间进行着高速的切换,对于 CPU 而言,某个时刻只能执行一个线程,而 CPU 在多个线程之间切换的速度很快,看上去就是在同一时刻运行,多线程程序并不能提高程序的运行速度,但是能够提高程序的运行效率,让 CPU 的使用率更高,
3、创建
1、Thread
新建一个类,继承 Thread ,重写 run()方法,run 方法内就是新线程要做的事,通过调用 start()方法来开启
public class Demo1 {
public static void main(String[] args) {
A a = new A();
a.start();
for (int i = 0;i < 10;i++) {
System.out.println(i);
}
}
}
class A extends Thread{
@Override
public void run() {
for (int i = 10;i < 20;i++) {
System.out.println(i);
}
}
}
2、Runnable
实现 Runnable 接口,重写 run()方法,run 方法内就是新线程要做的事,将实现 Runnable 的对象传给 Thread 对象,再通过 Thread 对象调用 start()方法,
public class Demo1 {
public static void main(String[] args) {
A a = new A();
Thread t = new Thread(a);
//t.setDaemon(true);设置为守护线程
t.start();
for (int i = 0;i < 10;i++) {
System.out.println(i);
}
}
}
class A implements Runnable{
@Override
public void run() {
for (int i = 10;i < 20;i++) {
System.out.println(i);
}
}
}
4、守护线程
用户线程:我们创建的每一个线程都是用户线程,当一个进程不包含任何的存活(运行)的用户线程时,运行结束,
守护线程:用于守护用户线程,当最后一个用户线程结束时,所有守护线程会自动结束,在调用 start()方法前,调用 setDaemon(true)方法,可将线程设置为守护线程
5、线程安全
当多个线程对数据进行操作时,可能会发生数据错乱的问题
1、同步代码块(隐式锁)
synchronize(锁对象){需要同步的代码块}
锁对象必须是同一个才能起到效果。
2、同步方法(隐式锁)
synchronize修饰方法,将需要排队执行的方法锁住,如果方法不是静态的,那么它的锁对象是this,如果是静态的,那么它的锁对象是 类名.class,当有多个方法被synchronize修饰时,有一个方法被使用,其他的方法也会被锁住
3、显示锁
Lock l = new ReentrantLock();
l.lock();//上锁
....//需要锁住的内容
l.unlock();//开锁
4、公平锁和非公平锁
公平锁:先来先用
Lock l = new ReentrantLock(true);//显示锁在创建时传入 true 为公平锁
l.lock();//上锁
....//需要锁住的内容
l.unlock();//开锁
非公平锁:谁抢到谁用(java默认)
5、线程死锁
A 调用了 B,B 调用了 A,但是因为锁住了,所以 A 在等 B 执行完,而 B 也在等 A 执行完,就这样卡住了
public class Demo2 {
public static void main(String[] args) {
//线程死锁
Culprit c = new Culprit();
Police p = new Police();
new MyThread(c,p).start();
c.say(p);
}
static class MyThread extends Thread{
private Culprit c;
private Police p;
MyThread(Culprit c,Police p){
this.c = c;
this.p = p;
}
@Override
public void run() {
p.say(c);
}
}
static class Culprit{
public synchronized void say(Police p){
System.out.println("罪犯:你放了我,我放了人质");
p.fun();
}
public synchronized void fun(){
System.out.println("罪犯被放了,罪犯也放了人质");
}
}
static class Police{
public synchronized void say(Culprit c){
System.out.println("警察:你放了人质,我放了你");
c.fun();
}
public synchronized void fun(){
System.out.println("警察救了人质,但是罪犯跑了");
}
}
}
6、多线程通信
使用 Object 类中的 wait()方法休眠和 notifyAll()方法唤醒,
7、线程池
1、缓存线程池
//创建:ExecutorService service = Executors.newCachedThreadPool();
//service.execute()方法调用
2、定长线程池
//创建:ExecutorService service = Executors.newFixedThreadPool(长度);
//service.execute()方法调用
3、单线程线程池
//创建:ExecutorService service = Executors.newSingleThreadPool();
//service.execute()方法调用
4、周期性任务定长线程池
//创建ScheduleExecutorService service = Executors.newScheduleThreadPool(长度);
//分两种:1、定时执行,2、周期性执行