[java]9、多线程
2021-10-08 本文已影响0人
史记_d5da
1、开启新线程
1)、创建一个Thread类的子类
2)、在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么?)
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println("run:"+i);
}
}
}
线程执行原理
2、线程名称
public class MyThread extends Thread{
// 设置线程名称
public MyThread(String name) {
super(name);
}
@Override
public void run() {
// 获取线程名称
System.out.println(getName());
System.out.println(Thread.currentThread().getName());
}
}
3、创建线程的第二种方式
public class RunnableImpl implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
// 启动线程
RunnableImpl run = new RunnableImpl();
Thread t = new Thread(run);
t.start();
实现Runnable接口创建多线程的好处
1)、避免了单继承的局限性,一个类只能继承一个类(一个人只能有一个亲爹),类继承了Thread类就不能继承其他的类,实现了Runnable接口,还可以继承其他类,实现其他接口
2)、增强了程序的扩展性,降低了程序的耦合性
4、线程同步
1)、synchronized实现线程同步锁
2)、静态代码块实现多线程 同步
private int ticket = 100;
/* 同步方法的锁对象,new RunnableImp() 也就是this*/
public synchronized void payTicket() {
// synchronized (this) {
System.out.println(Thread.currentThread().getName() + "正在卖第:" + ticket + "张票");
ticket--;
// }
}
private static int ticket = 100;
/* 静态方法的锁对象是本类的class属性 */
public static synchronized void payTicket() {
System.out.println(Thread.currentThread().getName() + "正在卖第:" + ticket + "张票");
ticket--;
}
3)、lock实现锁
public class RunnableImp implements Runnable {
Lock l = new ReentrantLock();
private int ticket = 100;
@Override
public void run() {
while (ticket > 0) {
l.lock();
if (ticket > 0) {
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "正在卖第:" + ticket + "张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
} finally { // 无论程序是否发生异常,都会把锁对象释放
l.unlock();
}
}
}
}
}
5、线程状态
线程状态使用Object的 wait() 和 notify()实现生产者和消费者关系
public class Demo10 {
public static void main(String[] args) {
// 创建锁对象,保证唯一
Object obj = new Object();
new Thread() {
@Override
public void run() {
// 保证等待和唤醒的线程只能有一个执行,需要同步机制
synchronized (obj) {
System.out.println("告知老板要的包子的种类和数量");
try { // 调用wait 进入等待状态
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 唤醒之后的代码
System.out.println("包子做好了,开吃");
}
}
}.start();
// 创建一个老板线程
new Thread(){
@Override
public void run() {
// 花了5s做包子
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
System.out.println("老板5s之后做好包子,告知顾客,可以吃包子");
// 唤醒顾客吃包子
obj.notify();
// notifyAll(); 唤醒所有等待线程
}
}
}.start();
}
}
6、线程池
// RunnableImpl
public class RunnableImpl implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
// ----------------------------------------------------------------------
// main
// 使用线程池的工厂类 Executors里面提供的静态方法newFixedThreadPool 产生指定数量的线程池
ExecutorService es = Executors.newFixedThreadPool(2);
// 调用ExecutorService中的方法submit,传递线程任务,开启线程,执行run方法
es.submit(new RunnableImpl()); // pool-1-thread-1
es.submit(new RunnableImpl()); // pool-1-thread-2
// 线程池会一直开启,使用完了线程,会自动把线程归还给线程池,线程可以继续使用
es.submit(new RunnableImpl()); // pool-1-thread-2
// 调用shutdown销毁线程池(线程池销毁,不建议使用)
es.shutdown();