多线程指多任务同时执行。
一、创建线程和开启
(方法一)继承Thread类,重写run()方法
- 定义线程体:
public class Test extends Thread{
//定义线程体
@Override
public void run() {
for(int i=1;i<=100;i++){
System.out.println("aaa");
}
}
}
- 开启多线程
public static void main(String[] args) {
//创建线程对象:创建Thread子类的对象
ThreadDemo01 th=new ThreadDemo01();
//开启线程
th.start();
//在开启线程后,run()中的代码和start()后的代码会同时执行,执行顺序由cpu决定。
for(int i=1;i<=100;i++){
System.out.println("bbb.....");
}
}
(方法二)实现Runnable接口,重写run()方法
**优点:**避免单继承的局限性,实现资源共享。推荐使用。
- 定义线程体:
public class Test implements Runnable{
//定义线程体
@Override
public void run() {
for(int i=1;i<=100;i++){
System.out.println("aaa");
}
}
}
- 开启多线程
public static void main(String[] args) {
ThreadDemo02 th=new ThreadDemo02();
Thread t=new Thread(th);
//虽然由Runnable接口实现,但是Runnable接口没有开启多线程的方法,所以还需要Thread类来开启多线程。
t.start();
for(int i=1;i<=100;i++){
System.out.println("bbb.....");
}
}
(方法三)实现Callable接口,重写call()方法
优点: call() 可以有返回值,且可以抛出异常
缺点: 操作复杂,不建议使用
- 定义线程体:
public class T3 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int i;
for(i=1;i<=20;i++){
if(i>=10)
System.out.println(i+"学习...");
else
System.out.println(i+"吃饭...");
}
return i;
}
}
- 开启多线程
public static void main(String[] args) throws InterruptedException, ExecutionException {
T3 th = new T3();
//创建服务
ExecutorService ex = Executors.newFixedThreadPool(2);
//提交执行
Future<Integer> re1 = ex.submit(th);
Future<Integer> re2 = ex.submit(th);
//获取返回值
Integer i1= re1.get();
Integer i2= re2.get();
System.out.println(i1+"--->"+i2);
//关闭服务
ex.shutdown();
}
二、线程状态
- 新生: new Thread()
- 就绪: start(),就绪状态的线程会进入到就绪队列中,等待cpu调度
- start()
- 阻塞状态解除
- yield()礼让线程:让出cpu的资源,线程直接进入就绪状态,但是下次cpu可能还会调用自己。
- 线程切换
- 运行: 当cpu分配时间片给线程,这个线程就会进入运行状态开始运行
- 阻塞:
- sleep():线程睡眠时会进入阻塞状态,让出CPU资源,但不会释放对象锁。
- wait()
- join():插队,强行执行某线程
- IO操作
- 终止: 线程结束
- 正常执行完毕
- 添加外部标识进行判断
- stop()、destory()已过时
sleep()
作用
- 放大发生问题的可能性
- 模拟网络延迟
public class Test implements Runnable{
public static void main(String[] args) {
new Thread(new Test()).start();
}
//模拟网络延迟
@Override
public void run() {
for(int i=10;i>=0;i--){
if(i==0){
System.out.println("开始");
break;
}
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
yield()
public class YieldDemo {
static class Inner implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"结束执行");
}
}
public static void main(String[] args) {
Inner in=new Inner();
new Thread(in,"A" ).start();
new Thread(in,"B" ).start();
}
}
join()
public class JoinDemo {
public static void main(String[] args) {
new Thread(new TimeD()).start();
}
}
class TimeD implements Runnable{
@Override
public void run() {
System.out.println("开始倒计时");
Thread th=new Thread(new st());
th.start();
th.join();//强行执行倒计时
System.out.println("结束倒计时");
}
}
class st implements Runnable{
@Override
public void run() {
for(int i=1;i<=10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
getStart():返回线程的枚举类型状态值
NEW
至今尚未启动的线程处于这种状态。RUNNABLE
正在 Java 虚拟机中执行的线程处于这种状态。BLOCKED
受阻塞并等待某个监视器锁的线程处于这种状态。WAITING
无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。TIMED_WAITING
等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。TERMINATED
已退出的线程处于这种状态。
int getPriority() 返回线程的优先级。
void setPriority(int newPriority) 更改线程的优先级。
- 线程的优先级: 1~10 ,1为最小,10为最大,默认为5
- 设置优先级无法控制线程执行顺序,但是可以增加执行的可能性。
三、线程安全
当多线程,同时操作,同一份资源的时候有可能存在线程不安全问题。
控制线程安全:使用同步锁 synchronized
锁静态方法:public synchronized static
public class Test implements Runnable{
static int food = 100;
/*
* 学生买饭
*/
public void run() {
go();
}
public synchronized static void go() {
while(true){
//判断饭是否卖完
if(food<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了一份,还剩"+food--+"份饭");
}
}
public static void main(String[] args) {
Test t1=new Test(); //100
//创建线程 资源共享
Thread th1=new Thread(t1,"张三");
Thread th2=new Thread(t1,"李四");
Thread th3=new Thread(t1,"王五");
Thread th4=new Thread(t1,"赵六");
th1.start();
th2.start();
th3.start();
th4.start();
}
}
锁成员方法
public class Test implements Runnable{
int food = 100;
/*
* 学生买饭
*/
@Override
public synchronized void run() {
while(true){
//判断饭是否卖完
if(food<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了一份,还剩"+food--+"份饭");
}
}
public static void main(String[] args) {
Test t1=new Test(); //100
//创建线程 资源共享
Thread th1=new Thread(t1,"张三");
Thread th2=new Thread(t1,"李四");
Thread th3=new Thread(t1,"王五");
Thread th4=new Thread(t1,"赵六");
th1.start();
th2.start();
th3.start();
th4.start();
}
}
锁对象:synchronized(this){ }
public class Test implements Runnable{
//锁对象:每个对象只有一把锁,对象锁释放,别人就获取不了
//对象中的所有资源都锁住了,只想要锁某一个资源,推荐锁资源
int food = 100;
/*
* 学生买饭
*/
@Override
public void run() {
while(true){
//判断饭是否卖完
synchronized (this) { //指代调用成员方法的对象
if(food<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了一份,还剩"+food--+"份饭");
}
}
}
public static void main(String[] args) {
Test t1=new Test(); //100
//创建线程 资源共享
Thread th1=new Thread(t1,"张三");
Thread th2=new Thread(t1,"李四");
Thread th3=new Thread(t1,"王五");
Thread th4=new Thread(t1,"赵六");
th1.start();
th2.start();
th3.start();
th4.start();
}
}
锁类:synchronized(类){ }
public class Test implements Runnable{
//锁类: 锁住了类的所有内容-->锁住了这个类的所有对象,锁住了一个对象中的所有资源,如果只想要锁一个对象建议去所对象
int food = 100;
/*
* 学生买饭
*/
@Override
public void run() {
while(true){
//判断饭是否卖完
synchronized (Test.class) {
if(food<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了一份,还剩"+food--+"份饭");
}
}
}
public static void main(String[] args) {
Test t1=new Test(); //100
//创建线程 资源共享
Thread th1=new Thread(t1,"张三");
Thread th2=new Thread(t1,"李四");
Thread th3=new Thread(t1,"王五");
Thread th4=new Thread(t1,"赵六");
th1.start();
th2.start();
th3.start();
th4.start();
}
}
锁资源:synchronized(资源){ }
自定义引用数据类型的对象地址永远不变
public class Test implements Runnable{
Food food=new Food();
/*
* 学生买饭
*/
@Override
public void run() {
while(true){
//判断饭是否卖完
synchronized (food) {
if(food.num<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了一份,还剩"+food.num--+"份饭");
}
}
}
public static void main(String[] args) {
Test t1=new Test(); //100
//创建线程 资源共享
Thread th1=new Thread(t1,"张三");
Thread th2=new Thread(t1,"李四");
Thread th3=new Thread(t1,"王五");
Thread th4=new Thread(t1,"赵六");
th1.start();
th2.start();
th3.start();
th4.start();
}
}
class Food{
int num=100;
}
四、线程通信
wait():线程等待,会让出对象的锁,并让出cpu的资源,对象进入阻塞状态。
notify() :线程唤醒,使对象加入就绪状态
线程通信解决多线程之间共享数据的处理,wait() 和 notify()继承自Object类,使用wait() 和 notify()必须在一个安全同步的环境下
如果没有在同步环境下会抛出异常:IllegalMonitorStateException