线程
一、内容回顾
1、java集合框架的组成
2、ArrayList和LinkedList的区别是什么
3、ArrayList是如何添加数据的
4、HashMap是如何存放数据的
5、如何给ArrayList中的对象按某个属性排序?
6、java处理异常的方式有哪些?
7、Throw和Throws的区别是什么?
8、遍历Map集合有哪些方式?
二、今日内容
1、进程和线程的区别
2、java的线程实现方式
3、线程的状态及状态的转换
4、后台线程、线程让步、线程优先级等
1、进程和线程的区别
进程:就是一个运行的程序,默认有一个主线程
线程:是进程中的一个任务,在一个进程中可以同时执行多个任务,称为多线程
2、java多线程实现方式
1、继承Thread类
package com.qf.pro2103.day18;
public class Thread1 extends Thread {
public void run(){
//任务
for(int j=1; j<=10; j++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("j="+j);
}
}
}
package com.qf.pro2103.day18;
public class Demo2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName());
Thread1 t1=new Thread1();
Thread2 t2=new Thread2();
t1.start();//可以让CPU执行任务run(),但不是立刻执行
t2.start();
for(int k=1;k<=10;k++){
System.out.println("k="+k);
}
}
}
2、实现Runnable接口
package com.qf.pro2103.day18;
public class Thread3 implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for(int k=1;k<=10;k++){
System.out.println("k="+k);
}
}
}
package com.qf.pro2103.day18;
public class Demo3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread3 t3=new Thread3();
Thread4 t4=new Thread4();
Thread t31=new Thread(t3);
Thread t41=new Thread(t4);
t31.start();
t41.start();
}
}
推荐:使用接口方式实现多线程
3、线程状态
出行运行状态的线程进入到阻塞状态的方式之一:sleep(毫秒),在休眠时间结束后,自动进入到就绪状态
4、线程常见方法:
sleep(毫秒): 正在执行状态的线程,执行了sleep方法后就阻塞进入休眠状态,待休眠时间结束后,此线程自动进入就绪状态。
yield()线程放弃,正在执行的线程,如果执行了yield方法,此线程由执行状态转变为就绪状态,等待CPU再次轮转
join()线程结合,插队 当前线程正在执行过程中,如果某个线程执行了join(),则优先执行该线程,待该线程执行后,继续执行被插队的线程
setPriority(10); //级别的数值越大,被CPU先执行的几率越高
t2.setDaemon(true); 设置为后台线程
5、线程安全问题:
多个线程操作同一“资源”
package com.qf.pro2103.day18;
public class MyArrayList implements Runnable {
public static int index=0; //记录数组存放数据的位置
public static String[] ary=new String[5];
@Override
public void run() {
// TODO Auto-generated method stub
ary[index]="hello";
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
index++;
}
}
package com.qf.pro2103.day18;
public class ThreadSafe {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyArrayList mal=new MyArrayList();
Thread t1=new Thread(mal);
Thread t2=new Thread(mal);
t1.start();
t2.start();
//输出数组内容
try {
Thread.sleep(1000);//线程给数组复制后,再执行下面的遍历
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String[] ary=MyArrayList.ary;
System.out.println("index="+MyArrayList.index);
for(int i=0; i<ary.length; i++){
System.out.println(ary[i]);
}
}
}
解决线程安全问题:使用锁
用锁把相关代码锁在一起,即使CPU轮转到其它线程,但是由于有锁,其它线程只能等待(阻塞),当锁释放后,其它线程竞争锁(CPU时间片轮转到哪个线程),
同步锁有两种用法:
1、同步代码块
synchronized(锁对象){
//锁住的代码
}
package com.qf.pro2103.day18;
public class MyArrayList implements Runnable {
public static int index=0; //记录数组存放数据的位置
public static String[] ary=new String[5];
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (this) {
ary[index]="hello";
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
index++;
}
}
}
2、同步方法
用法:在方法的返回值类型前加关键字synchronized,意味着方法中的所有代码都在锁的范围内。
6、死锁问题
两个线程,互相等待对象释放锁对象
package com.qf.pro2103.day18.deadlock;
public class FoodLock {
//任意非空对象都可以作为锁对象
//一个锁对象只能同时为一个线程作为锁对象使用
public static Object milk=new Object();
public static Object bread=new Object();
}
package com.qf.pro2103.day18.deadlock;
public class Teacher implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (FoodLock.bread) {
System.out.println("Teacher已经拿到了面包,等待拿到牛奶");
synchronized (FoodLock.milk) {
System.out.println("Teacher已经拿到了牛奶,可以吃早餐了!");
}
}
}
}
package com.qf.pro2103.day18.deadlock;
public class Student implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (FoodLock.milk) {
System.out.println("Student已经拿到了牛奶,等待获取面包");
synchronized (FoodLock.bread) {
System.out.println("Student拿到了面包,可以吃早餐了!");
}
}
}
}
package com.qf.pro2103.day18.deadlock;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student jia=new Student();
Teacher liu=new Teacher();
Thread t1=new Thread(jia);
Thread t2=new Thread(liu);
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
try {
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
避免死锁:
1、确定线程的先后执行顺序 join()
总结:
1、进程和线程区别
2、线程实现方式
3、线程的状态及状态的改变
4、重点:什么是线程安全问题
5、同步锁:两种用法
{
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
try {
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
避免死锁:
1、确定线程的先后执行顺序 join()
总结:
1、进程和线程区别
2、线程实现方式
3、线程的状态及状态的改变
4、重点:什么是线程安全问题
5、同步锁:两种用法
6、死锁问题