一. Thread
第一种创建线程的方式(创建线程的子类)
java.util.lang
包下的- 创建一个线程类继承Thread,要重写run方法
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(getName());
}
}
- 调用start方法,抢夺cpu
Tread mt = new MyThread();
mt.start();//开始与主程序一起运行,抢夺cpu,执行run中的内容
- 匿名内部类
new Thread(){
@Override
public void run() {
for(int i = 0; i < 20; i++)
{
System.out.println(Thread.currentThread().getName()+ "lwt");
}
}
}.start();
第二种创建线程的方式(Runnable)
- 创建Runnable的实现类RunnableImpl,实现run方法
public class RunnableImpl implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName()+ "创建了一个新的线程");
}
}
- 创建Runnable的实现类对象,创建Thread类对像并将Runnable的实现类对象传入构造函数中去
Runnable run = new RunnableImpl();
Thread thread = new Thread(run);
- 调用其start方法开始与主程序强夺cpu
thread.start();
- 匿名内部类
Object object = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized(object){
System.out.println("老板,来一个包子");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("顾客:开吃");
System.out.println("-----------");
}
}
}).start();
这种方法避免了单继承的局限性,解耦(增强拓展性)
Thread类的常用方法
1. String getName();
2. static Thread currentThread();
3. void setName("name");
4. 设置名字:创建带参数的构造方法
5. static void sleep(long mills)//休眠
二. 不同线程访问共享数据的解决办法
1. 同步代码块
- 锁对象可以是任意对象
- 必须保证多个线程使用的对象是同一个
- 锁对象的作用:同步代码块内部的内容锁住,只让一个线程在同步代码块里面执行
Object obj = new Object();//创建锁对象
synchronized (obj){
//访问共享数据的代码
}
2. 同步方法
- 把访问方法了共享数据的代码抽取出来,放到一个方法中
- 方法添加一个synchronized的修饰符
- 在run中调用
public static synchronized void 方法名()
{
}
这个的锁对象其实是本类的class属性(如RunnableImpl.class)
3. Lock锁(两个方法)
- void lock() 锁上
- void unlock() 解锁
- Lock是一个接口,其中的一个实现类ReentrantLock
private Lock lock = new ReentrantLock();
public void run() {
while (ticket > 0)
{
lock.lock();//锁上
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
lock.unlock();//解锁
}
}
三. 线程状态
- Time_waiting(睡眠状态)
这个用Thread.sleep()进入 - waiting(永久等待)
object.wait()
object.notify()
四. 进程间的通信,等待唤醒案例
- 同步代码块锁上控制资源,然后用wait,notify来控制进程
//Baozi.java
package practice.Demo05Thread;
public class Baozi {
private String pi;
private String xian;
private boolean flag = false;
public String getPi() {
return pi;
}
public void setPi(String pi) {
this.pi = pi;
}
public String getXian() {
return xian;
}
public void setXian(String xian) {
this.xian = xian;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
//Baozipu.java
import java.util.concurrent.ThreadLocalRandom;
public class Baozipu extends Thread{
private Baozi baozi;
public Baozipu(Baozi baozi){
this.baozi = baozi;
}
@Override
public void run() {
int count = 0;
while (true)
{
synchronized (baozi)
{
if(baozi.isFlag())
{
try {
//有包子就等待,不用包子
baozi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 开始生产包子
if(count % 2 == 0)
{
//生产牛肉薄馅
baozi.setPi("薄皮");
baozi.setXian("牛肉");
}else if(count % 2 == 1)
{
baozi.setPi("厚皮");
baozi.setXian("葱花");
}
count++;
System.out.println("包子铺正在生产: "+ baozi.getPi()+baozi.getXian() +"的包子");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
baozi.setFlag(true);
//唤醒顾客吃包子
baozi.notify();
}
}
}
}
//Chihuo.java
public class Chihuo extends Thread {
private Baozi baozi;
public Chihuo(Baozi baozi)
{
this.baozi = baozi;
}
@Override
public void run() {
while(true)
{
synchronized (baozi)
{
if (!baozi.isFlag())
{
try {
baozi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//现在有包子了,开始吃
System.out.println("游客开始吃"+baozi.getXian()+baozi.getPi() + "的包子");
baozi.setFlag(false);
//唤醒包子铺做包子
baozi.notify();
System.out.println("游客已经吃完包子了");
}
}
}
}
//Demo.java
package practice.Demo05Thread;
public class Demo {
public static void main(String[] args) {
Baozi baozi = new Baozi();
new Baozipu(baozi).start();
new Chihuo(baozi).start();
}
}
五. 线程池
- 自从jdk1.5之后就提供线程池
- Java.util.concurrent.Executors中有一个静态方法
Static ExecutorService newFixedThreadPool(int n)
返回值一个实现类的对象 - 这个实现类对象含有的方法
取出线程Thread t = ex.submit(Runnable Task)
关闭线程池,不建议使用void shutdown()
public static void main(String[] args) {
ExecutorService ex = Executors.newFixedThreadPool(2);
ex.submit(new RunnableImpl());
ex.submit(new RunnableImpl());
ex.submit(new RunnableImpl());
ex.submit(new RunnableImpl());
ex.shutdown()