进程指的是程序执行的基本单位,程序由一个或者多个进程组成。线程指的是CPU执行的基本单位,进程是有一个或者多个线程组合合成。线程是由CPU调度执行,多线程是CPU不断地来回切换调度不同的线程执行的结果。
多线程的创建方式:1、自定义线程类继承Thread类,重写run()方法,main方法实例化自定义线程类,通过对象调用start()开启线程
2、自定义任务类实现Runnable接口,重写run()方法,main方法实例化自定义任务类,实例化Thread类并在构造方法中传递任务类的对象,通过Thread类对象调用start()开启线程
3、自定义类实现Callable接口,重写call(),拥有返回值
4、通过线程池启动线程
public class Demo01 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
//调用方法
//myThread.run();
//启动线程
myThread.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
}
}
public class Demo02 {
public static void main(String[] args) {
Task task = new Task();
Thread thread = new Thread(task);
thread.start();
}
}
class Task implements Runnable{
@Override
public void run() {
}
}
线程池可以实现线程的重复使用,减少线程的创建和销毁时间
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo04{
public static void main(String[] args){
/*//创建一条线程的线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
//创建10条线程的线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
//自带缓冲区的线程池
ExecutorService pool = Executors.newCachedThreadPool();
Task task = new Task();
for(int i=0;i<10;i++){
//把任务提交给线程池
pool.submit(task);
}
//关闭线程池
pool.shutdown();*/
}
}
class Task implements Runnable{
@Override
public void run(){
//Thread.currentThread().getName() 获取当前线程的名字
}
}
线程的安全问题:多个线程同时访问异步临界资源,可能会造成数据混乱,因此需要给线程加上同步锁,同步锁分为两类:synchronize和lock。
synchronize:
一、同步代码块:需要同步的代码放在同步代码块中,添加同步锁和同步监视器。要求多个线程访问的时候,使用的是同一个对象的同步监视器,当有线程进入同步代码块,其他线程则会等待进入同步代码块的线程执行完毕后才会进入(案例一)
二、同步方法:被同步锁修饰的方法为同步方法,同步监视器为方法本身。当一条线程调用同步方法时,其他线程则会等待同步方法执行完毕再调用,要求方法为静态方法或者使用同一个对象(案例二)
/*10个外星人电脑专售店,出售1000台外星人电脑
第1家外星人电脑专售店出售第1台电脑
第9家外星人电脑专售店出售第2台电脑
第4家外星人电脑专售店出售第3台电脑
第10家外星人电脑专售店出售第4台电脑
第2家外星人电脑专售店出售第5台电脑
...
第4家外星人电脑专售店出售第1000台电脑
第4家外星人电脑专售店已售罄
第2家外星人电脑专售店已售罄
第1家外星人电脑专售店已售罄
第9家外星人电脑专售店已售罄
第10家外星人电脑专售店已售罄
...*/
//案例一
public class Demo01{
public static void main(String[] args){
for(int i = 1; i <= 10;i++){
new MyThread("第"+i+"家