线程:
java程序属于抢占式调度,那个线程的优先级高,那个线程先执行;同一优先级,随机选择一个
获取线程名称: getName() currentThread() 当前线程的名称
Thread.currentThread().getName()
Runnable 的实现类中,没有getName方法
设置线程名称:
1.使用Thread类中的方法setName(名字)改变线程名称,使之与参数相同
2.创建一个带参数的构造方法,参数传递线程名称;调用父类的带参构造方法,把线程名称传递给父类,让父类給子线程起一个名字
线程优先级
1、线程谁先运行谁后运行的级别
2、Thread类中的setPriority设定优先级
3、setPriority(int status)
Status:从1-10,数字越大,优先级越高,越提前执行
4、三个常量:
MAX_PRIORITY 10
MIN_PRIORITY 1
NORM_PRIORITY 5 默认的优先级
创建多线程程序
创建多线程程序的第一种方式:创建Thread类的子类
java.lang.Thread类,我们想要实现多线程程序,就必须继承Thread类
实现步骤:
1.创建一个Thread类的子类
2.在Thread类的子类中重写Thread类中的run方法,设置线程任务
3.创建Thread类的子类对象
4.调用Thread类中的方法start方法,开启新的线程,执行run方法,当前线程(main)和另一个线程(创建的新的线程)并发的运行,多次启动一个线程是非法的,特别是当线程已经结束后,就不能在重新启动
创建多线程程序的第二种方式:实现 Runnable接口
java.Lang.Runnable
Runnable接口应给由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为一个run的无参数构造方法。
java.lang.Thread类的构造方法
Thread( Runnable target)分配新的 Thread对象
Thread( Runnable target, string name)分配新的 Thread对象。
实现步骤:
1.建一个 Runnable接囗的实现类
2.在实现类中重写 RunnabLe接口的run方法,设置线程任务
3.创建一个 Runnable接口的实现类对象
4.创建 Thread类对象,构造方法中传递 Runnable接口的实现类对象
5.调用 Thread类中的 start方法,开启新的线程执行ru方法
创建多线程程序的第三种方式:使用匿名内部类方法
new Thread() {
@Override
public void run() {
for (int i = 0;i<10 ;i++) {
System.out.println("thread: "+Thread.currentThread().getName());
}
}
}.start();;
Runnable r = new Runnable() {
@Override
public void run() {
for (int i = 0;i<10 ;i++) {
System.out.println("runnable: "+Thread.currentThread().getName());
}
}
};
new Thread(r).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0;i<10 ;i++) {
System.out.println("简化runnable接口: "+Thread.currentThread().getName());
}
}
}).start();
解决线程安全问题的一种方案:使用同步代码块
格式:
synchronized(锁对象){
可能会出现线程安全的代码(访问了共享数据的代码)
}
注意:
1.通过代码块中的锁对象,可以使用任意的对象
2.但必须保证多线程使用的锁对象是同一个
3.锁对象作用
把同步代码块锁住,只让一个线程在同步代码块中执行
class RunnableImp2 implements Runnable {
private int ticket = 10;
Object obj = new Object();
@Override
public void run() {
while(true) {
synchronized (obj) {
if (ticket > 0) {
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+"-->"+"正在卖第"+ticket+"票");
ticket--;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
解决线程安全问题的二种方案:使用同步方法
使用步骤:
1.把访问了共享数据的代码抽取出来,放到一个方法中
2.在方法上添加synchronied修饰符
格式:
修饰符 synchronized 返回值类型 方法名(参数列表){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意:
同步方法也会把方法内部的代码锁住,只让一个线程执行
同步方法的锁对象是谁?
就是实现类对象 new RunnableImpl(),也就是this
使用静态同步方法
锁对象是谁?
不能是this,this是创建对象之后产生的,静态方法优于对象,静态方法的锁对象是本类的class属性-->class文件对象(反射)
解决线程安全问题的三种方案:使用Lock锁
java.util.concurrent.locks.Lock接口
Lock实现提供了比使用synchronized 方法和语句获得更广泛的锁操作。
Lock接口中的方法:
void lock()获得锁
void unlock()释放锁
java.util.concurrent.Locks.ReentrantLock implements Lock接口
使用步骤:
1.在成员位置创见一个ReentrantLock对象
2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁
同步锁是谁?
对于非静态的方法,同步锁就是this
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)
等待唤醒案例:线程之间的通信
创建一个顾客线程:告知老板要的包子的种类和数量,调用wait方法,放弃cpu的执行,进入到WAITING状态(无限等待)
创建一个老板线程:花5秒做包子,做好包子之后,调用notify方法,唤醒顾客吃包子
注意:
顾客和老板之间必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行
同步使用的锁对象必须保证唯一
只有锁对象才能调用wait和notify方法
Object类中的方法
void wait()
在其他线程调用此对象的notify()方法或者 notifyAll()方法前,导致当前线程等待
void notify()方法
唤醒在此对象监视器等待的单个线程
会继续执行wait()方法之后的代码
notifyAll()方法
唤醒所有的线程
Object obj = new Object();
new Thread() {
@Override
public void run() {
synchronized (obj) {
System.out.println("告知老板要的数量与种类");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("包子做好了,开吃");
}
}
}.start();
new Thread() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
System.out.println("老板花了五秒做好了包子,告知顾客");
obj.notify();
}
}
}.start();
解决线程安全问题
public class BaoZi {
String pi;
String xian;
boolean flag = false;
}
public class BaoZiPu extends Thread{
private BaoZi bz;
public BaoZiPu(BaoZi bz) {
this.bz = bz;
}
@Override
public void run() {
int count = 0;
while(true) {
synchronized (bz) {
if (bz.flag == true) {
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count % 2 == 0) {
bz.pi = "薄皮";
bz.xian = "三鲜馅";
}else {
bz.pi = "冰皮";
bz.xian = "牛肉大葱";
}
count++;
System.out.println("包子铺正在生产包子"+bz.pi+bz.xian+"包子");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bz.flag = true;
bz.notify();
System.out.println("包子铺生产好了"+bz.pi+bz.xian+"包子");
}
}
}
}
public class BaoZiChiHuo extends Thread{
private BaoZi bz;
public BaoZiChiHuo(BaoZi bz) {
this.bz = bz;
}
@Override
public void run() {
while(true) {
synchronized (bz) {
if (bz.flag == false) {
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("吃货正在吃"+bz.pi+bz.xian+"包子");
bz.flag = false;
bz.notify();
System.out.println("吃货已经吃完了"+bz.pi+bz.xian+"包子吃完了,包子铺开始生成包子");
System.out.println("-----------------------");
}
}
}
}
public class BaZiTest {
public static void main(String[] args) {
BaoZi bz = new BaoZi();
new BaoZiPu(bz).start();
new BaoZiChiHuo(bz).start();
}
}
线程池: JDK1.5之后提供的
java.util.concurrent.Executors:线程池的工厂类,用来生成线程池
Executors类中的静态方法
static ExecutorService newFixedThreadpooL( int nthreads)
static ExecutorService newSingleThreadPool(): 生成一个具有一条线程的线程池
创建一个可重用固定线程数的线程池
参数:int nthreads:创建线程池中包含的线程数量
返回值:
Executorservice接口,返回的是 Executorservice接口的实现类对象
我们可以使用 Executorservice接口接收(面向接口编程)
java.util.concurrent.Executorservice:线程池接口
用来从线程池中获取线程,调用 start方法,执行线程任务
submit( Runnable task)提交一个 Runnable任务用于执行
关闭销毁线程池的方法
1、shutDown()
终止线程池的提交功能,已经提交的会都执行完
2、List<Runnable> shutDownNow
关闭线程池,返回还没有执行的任务,已经在运行的就执行完
线程池的使用步骤
1.使用线程池的工厂类 Executors里边提供的静态方法 newFixedThreadpooL生产一个指定线程数量的线程池
2.创建一个类实现 Runnable接口,重写run方法,设置线程任务
3.调用 ExecutorServicel中的方法 submit,传递线程任务(实现类),开启线程,执行run方法
4.调用 Executorservice中的方法 shutdown销毁线程池(不建议执行)
例子:
class RunbleImp implements Runnable {
@Override
public void run() {
for (int j = 0; j < 5; j++) {
System.out.println(Thread.currentThread().getName()+" hello");
}
}
}
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new RunbleImp());
es.submit(new RunbleImp());
线程状态
1. 状态类型
1、新建态:线程对象刚创建
2、就绪态:准备好了运行,只要调用了start方法的线程,都是就绪态
3、运行态:cpu正在处理和操作的线程
4、阻塞态:线程休眠、线程等待、等待同步锁、I/O的时候都是阻塞态
5、死亡态:线程正常运行结束或者被人为终止
2、专门的类型:
Thread.State,是枚举类型,该类中的对象是有限个的,提前创建好的
3、枚举项:
NEW:新建态
RUNNABLE:就绪态和运行态
BLOCKED:等待同步锁的阻塞状态
WAITING:等待其他线程唤醒的状态
TIMED_WAITING:有时间限制的休眠状态
TERMINATED:死亡态
4、获取线程状态:
Thread.State getState()
获取调用者线程的状态