1. 创建线程的三种方法
- 继承Thread类【重点】
- 继承Thread类,重写run()方法,调用start开启线程
- 不建议使用:
避免OOP单继承局限性
//创建线程的方式一:继承Thread类,重写run()方法,调用start开启线程
public class Thread_one extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("Thread_one......");
}
}
public static void main(String[] args) {
//创建一个线程对象
Thread_one thread = new Thread_one();
//调用strat()方法调用线程
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("main......");
}
}
}
- 实现Runnable接口【重点】
- 实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
- 推荐使用:
避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
//创建线程的方式二:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
public class Thread_two implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("Thread.......");
}
}
public static void main(String[] args) {
Thread_two thread_runnable = new Thread_two();
Thread thread = new Thread(thread_runnable);
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("main......");
}
}
}
- 实现Callable接口【了解】
- 实现Callalbe接口中的call方法。创建执行服务,提交执行,获取结果,关闭服务。
//创建线程的方式三:实现Callalbe<T>接口中的call方法。创建执行服务,提交执行,获取结果,关闭服务。
public class Thread_three implements Callable<Boolean>{
private String name;
public Thread_three(String name) {
this.name = name;
}
@Override
public Boolean call() throws Exception {
for (int i = 0; i < 20; i++) {
System.out.println(this.name +"执行了...");
}
return true;
}
public static void main(String[] args) {
Thread_three t1 = new Thread_three("t1");
Thread_three t2 = new Thread_three("t2");
Thread_three t3 = new Thread_three("t3");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r1 = ser.submit(t1);
Future<Boolean> r2 = ser.submit(t2);
Future<Boolean> r3 = ser.submit(t3);
//获取结果
try {
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//关闭服务
ser.shutdown();
}
}
2. 线程的方法
- 线程五大状态:创建状态,就绪状态,运行状态,阻塞状态,死亡状态
- 线程方法
方法 | 说明 |
---|---|
setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止 |
static void yield | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt | 中断线程,别用这个方式 |
boolean isAlive | 测试线程是否处于活动状态 |
- 线程停止
/**
* 线程的停止
* 1. 建议线程正常停止---> 利用次数,不建议死循环
* 2. 建议使用标志位---> 设置一个标志位
* 3. 不要使用stop或者destroy等过时或者JDK不建议使用的方法
*/
public class Thread_stop implements Runnable{
//设置一个标志位
private boolean flag = true;
@Override
public void run() {
int i = 0;
while(flag) {
System.out.println("run ---> thread" + i++);
}
}
public void stop() {
this.flag = false;
}
public static void main(String[] args) {
Thread_stop stop = new Thread_stop();
for (int i = 0; i < 1000; i++) {
if(i == 900) {
stop.stop();
System.out.println("线程停止了......");
}
}
}
}
3. 守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕,如垃圾回收,监控内存等
Thread thread = new Thread()
thread.setDaemon(true) //开启守护线程
4. 线程同步
- 线程同步:多个线程操作同一个资源。
- 线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。
锁机制synchronized
同步方法和同步代码块
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station, "a").start();
new Thread(station, "b").start();
new Thread(station, "c").start();
}
}
class BuyTicket implements Runnable{
//票
private int ticketNums = 10;
boolean flag = true;
@Override
public void run() {
//买票
while(flag) {
try {
buy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//synchronized:同步方法,锁的是this
private synchronized void buy() throws InterruptedException{
//判断是否有票
if(ticketNums <= 0) {
flag = false;
return;
}
//模拟延时
Thread.sleep(100);
//买票
System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
}
//synchronized:同步代码块。锁的是变化的量
private void buy_() throws InterruptedException{
synchronized(ticketNums) {
//判断是否有票
if(ticketNums <= 0) {
flag = false;
return;
}
//模拟延时
Thread.sleep(100);
//买票
System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
}
}
}
锁机制
import java.util.concurrent.locks.ReentrantLock;
public class Lock {
public static void main(String[] args) {
testLock lock = new testLock();
new Thread(lock).start();
new Thread(lock).start();
new Thread(lock).start();
}
}
class testLock implements Runnable {
int ticketNums = 10;
//定义lock锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while(true) {
try {
//加锁
lock.lock();
if(ticketNums > 0) {
try {
Thread.sleep(1000);
System.out.println(ticketNums--);
} catch (Exception e) {
e.printStackTrace();
}
}else {
break;
}
}finally{
//解锁
lock.unlock();
}
}
}
}
锁的优先顺序:锁机制>同步代码块>同步方法
5. 线程通信
- 线程通信的几个方法
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,知道其他线程通知,与sleep不同,会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度 |
- 生产者消费者问题的解决方法
- 管程法:生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
public class Pc {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生产者
class Productor extends Thread {
SynContainer container;
public Productor(SynContainer container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("生产了" + i + "只鸡");
container.push(new Chicken(i));
}
}
}
//消费者
class Consumer extends Thread {
SynContainer container;
public Consumer(SynContainer container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了-->" + container.pop().id + "只鸡");
}
}
}
//产品
class Chicken {
int id;//产品编号
public Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer {
Chicken[] chickens = new Chicken[10];
int count = 0;
//生产者放入产品
public synchronized void push(Chicken chicken) {
//如果容器满了,就需要等待消费者消费
if(count == chickens.length) {
//通知消费者消费。生产等待
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
//如果没有满,我们就需要丢入产品
chickens[count] = chicken;
count++;
//可以通知消费者消费了
this.notifyAll();
}
//消费者消费产品
public synchronized Chicken pop() {
//判断能否消费
if(count == 0) {
//等待生产者生成,消费者等待
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
//如果可以消费
count--;
Chicken chicken = chickens[count];
//吃完了,通知生产者生产
this.notifyAll();
return chicken;
}
}
- 信号灯法
public class Pc2 {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生产者--> 演员
class Player extends Thread {
TV tv;
public Player(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i % 2 == 0) {
this.tv.play("中央一套");
}else {
this.tv.play("中央五套");
}
}
}
}
//消费者--> 观众
class Watcher extends Thread {
TV tv;
public Watcher(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//产品-->节目
class TV {
//演员表演的时候,观众等待
//观众观看,演员等待
String voice; //表演的节目
boolean flag = true;
//表演
public synchronized void play(String voice) {
if(!flag) {
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("演员表演了:" + voice);
//通知观众观看
this.notifyAll();
this.voice = voice;
this.flag = !this.flag;
}
//观看
public synchronized void watch() {
if(flag) {
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("观众观看了:" + voice);
//通知表演表演
this.flag = !this.flag;
}
}
6. 线程池
- 提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Pool {
public static void main(String[] args) {
//1.创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);
//2.使用线程
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//3.关闭连接
service.shutdown();
}
}
class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}