概述
线程是一个程序内部的一条执行路径,一般的main函数只有一条执行路径,那么这个程序就是单线程的程序。
多线程的实现
多线程实现主要有以下两种方式
方案一:继续Thread类
定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
创建MyThread类的对象
调用线程对象的start()方法启动线程(启动后还是执行run方法的)
class Hello extends Thread {
private String name;
public hello(String name) {
this.name = name;
}
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + "运行 " + i);
}
}
public static void main(String[] args) {
Hello h1=new Hello("A");
Hello h2=new Hello("B");
h1.start();
h2.start();
}
}
方案二:通过实现Runnable接口
实现步骤:
定义一个线程任务类MyThread实现Runnable接口,重写run()方法
创建MyThread任务对象
把MyThread任务对象交给Thread处理。
调用线程对象的start()方法启动线程
class MyThread implements Runnable{
private int ticket = 5; //5张票
public void run() {
for (int i=0; i<=20; i++) {
if (this.ticket > 0) {
System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--);
}
}
}
}
public class Code {
public static void main(String [] args) {
MyThread my = new MyThread();
new Thread(my, "1号窗口").start();
new Thread(my, "2号窗口").start();
new Thread(my, "3号窗口").start();
}
}
线程的休眠
代码演示
class hello implements Runnable {
public void run() {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + i);
}
}
public static void main(String[] args) {
hello he = new hello();
Thread demo = new Thread(he, "线程");
demo.start();
}
}
输出结果:结果每隔2s输出一个
线程的优先级
class hello implements Runnable {
public void run() {
for(int i=0;i<5;++i){
System.out.println(Thread.currentThread().getName()+"运行"+i);
}
}
public static void main(String[] args) {
Thread h1=new Thread(new hello(),"A");
Thread h2=new Thread(new hello(),"B");
Thread h3=new Thread(new hello(),"C");
h1.setPriority(8);
h2.setPriority(2);
h3.setPriority(6);
h1.start();
h2.start();
h3.start();
}
}
注意:不要误以为优先级越高就先执行。谁先执行还是取决于谁先去的CPU的资源、
同步和死锁
【问题引出】:比如说对于买票系统,有下面的代码:
package com.stx.threadDemo;
public class Ticket extends Thread{
private static int ticketNums = 100;
public static void main(String[] args) {
Ticket ticket1 = new Ticket();
Ticket ticket2 = new Ticket();
Ticket ticket3 = new Ticket();
ticket1.start();
ticket2.start();
ticket3.start();
}
@Override
public void run() {
while (true) {
if (ticketNums <=0) {
System.out.println("票已经售罄!");
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("售票窗口:" + Thread.currentThread().getName() + " 售出一张票," + "剩余票数为:" + (--ticketNums));
}
}
}
运行结果
【运行结果】:
售票窗口:Thread-2 售出一张票,剩余票数为:2
售票窗口:Thread-0 售出一张票,剩余票数为:1
售票窗口:Thread-1 售出一张票,剩余票数为:0
票已经售罄!
售票窗口:Thread-2 售出一张票,剩余票数为:-1
售票窗口:Thread-0 售出一张票,剩余票数为:-2
票已经售罄!
票已经售罄!
这里出现了-1,-2,显然这个是错的。,应该票数不能为负值。
如果想解决这种问题,就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,
其他的线程必须等到这个线程结束之后才能继续执行。
【同步代码块】:
语法格式:
synchronized(同步对象){
//需要同步的代码
}
正确代码演示:
package com.stx.threadDemo;
public class Ticket extends Thread{
private static int ticketNums = 100;
public static void main(String[] args) {
Ticket ticket1 = new Ticket();
Ticket ticket2 = new Ticket();
Ticket ticket3 = new Ticket();
ticket1.start();
ticket2.start();
ticket3.start();
}
@Override
public void run() {
while (true) {
synchronized (Ticket.class){
if (ticketNums <=0) {
System.out.println("票已经售罄!");
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("售票窗口:" + Thread.currentThread().getName() + " 售出一张票," + "剩余票数为:" + (--ticketNums));
}
}
}
}
线程池
ThreadPoolExecutor构造器的参数说明
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory, RejectedExecutionHandler handler)
代码演示:
1 创建任务
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "输出了:HelloWorld ==> ");
}
}
2 创建线程池并执行
ExecutorService pool = new ThreadPoolExecutor(3, 5 ,
6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy() );
Runnable target = new MyRunnable();
pool.execute(target);
pool.execute(target);
pool.execute(target);
执行策略说明:
(1)当前运行的线程数少于 corePoolSize ,则添加新的线程执行该任务。
(2)当前的线程数等于 corePoolSize ,同时阻塞队列未满,则将任务入队列,而不添加新的线程。
(3)阻塞队列已满同时池中的线程数小于maximumPoolSize ,则创建新的临时线程执行任务。 (4)阻塞队列已满同时池中的线程数等于maximumPoolSize ,则根据构造函数中的 handler 指定的策略来拒绝新的任务。