个人复习Day11
十一、线程
1.基本概念
1.程序:静态代码
2.进程:代码执行,动态执行过程,具有独立内存
3.线程:是进程的最小执行单位(main本身就是个线程),共享进程的资源
2. 线程
注意:线程的运行是不可预知的
2.1 创建线程的两种方式
1.extends Thread
public class Demo1 {
//main方法主线程,可以管理其他线程
public static void main(String[] args) {
MyThread t=new MyThread();
MyThread2 t2=new MyThread2();
//启动线程start方法
//t、t2的运行随机
t.start();
t2.start();
}
}
class MyThread extends Thread{
//线程方法run
public void run(){
for(int i=1;i<1000;i++){
System.out.println("t1");
}
}
}
class MyThread2 extends Thread{
//线程方法run
public void run(){
for(int i=1;i<1000;i++){
System.err.println("t2");
}
}
}
2.implements Runnable接口,实现接口的这个类不是线程
public class Demo2 {
public static void main(String[] args) {
Runnable r=new Runnable(){
@Override
public void run() {
for(int i=1;i<100000;i++){
System.out.println("r1");
}
}
};
//就是不再调用thread类的run方法,替换成runnable接口中的run方法
Thread t=new Thread(r);
t.start();
Thread t2=new Thread(()->{
for(int i=1;i<100000;i++){
System.err.println("r2");
}
});
t2.start();
}
}
2.2 线程常用的方法
注意:sleep()不会释放资源,wait()会释放资源
public class Demo3 {
//主线程
public static void main(String[] args) {
/*Thread t = new Thread(){
public void run(){*/
//Thread.currentThread()获取正在运行的线程对象
Thread th=Thread.currentThread();
//Thread.currentThread().getName()获取线程的名称
String str=Thread.currentThread().getName();
//Thread.currentThread().getId()获取线程的唯一标识
long id=Thread.currentThread().getId();
//Thread.currentThread().isAlive()判断线程是否还活着
boolean b=th.isAlive();
System.out.println(th);
System.out.println(str);
System.out.println(id);
System.out.println(b);
/* };
};
t.start();*/
}
}
/*
* sleep方法让线程休眠
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
/*for(int i=1;i<=10;i++){
System.out.println(i);
//让线程休眠时间单位为ms 1000ms=1s
//如果在休眠过程中被唤醒,会触发InterruptedException异常
Thread.sleep(1000);
}*/
for(int i=0;i<=10;i++){
int n=10-i;
Thread.sleep(1000);
System.out.println(n);
}
System.out.println("过年了");
}
}
/*
* join方法
* 等待一个线程执行结束
*/
public class Demo5 {
public static void main(String[] args) {
Thread t1=new Thread(){
public void run(){
for(int i=1;i<=10;i++){
System.out.println("1");
}
}
};
Thread t2=new Thread(()->{
for(int i=1;i<=10;i++){
System.out.println("2");
if(i==3){
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
},"线程2");
t2.start();
t1.start();
}
}
小练习
public class test {
public static void main(String[] args) {
Thread t1=new Thread(){
public void run(){
System.out.println("开始下载图片");
for(int i=0;i<=100;i++){
System.out.println("下载"+i+"%");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("下载完毕");
}
};
Thread t2=new Thread(()->{
System.out.println("显示图片");
try {
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("显示图片完成");
},"线程2");
t2.start();
t1.start();
}
}
/*
* 守护线程
* 线程可以分为:前台线程和后台线程(守护线程)
* 默认情况下,创建的都是前台线程
* 使用setDaemon(true),改变前台线程为后台线程
* 两种线程在创建和使用上没有区别
* 区别:如果前台线程结束,那么所有的后台线程也执行结束
*/
public class Demo6 {
public static void main(String[] args) {
Thread rose=new Thread(){
public void run(){
for(int i=1;i<=3;i++){
System.out.println("我要跳船");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("一起跳");
}
};
Thread jack=new Thread(){
public void run(){
while(true){
System.out.println("我不跳");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
rose.start();
//把线程设置为后台线程
jack.setDaemon(true);
jack.start();
}
}
2.3 线程的生命周期
- 新建状态:new Thread();
- 就绪状态:start方法(接收调度)
- 运行状态:run方法(线程体方法)
- 阻塞状态(让出CPU资源):sleep(1000)、wait()、I/O
- 死亡状态:运行完run方法的最后一条语句
2.4 线程调度
同一优先级:先到先服务
不同优先级:优先极高的先运行,然后优先级低的运行
2.5 优先级
系统默认:1、5、10,一般都是中等优先级
人为设置:(内存足够时优先级并没有太大影响)
//设置线程优先级
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.NORM_PRIORITY);
t3.setPriority(Thread.MAX_PRIORITY);
2.6线程的同步
- 为什么实现同步:多个线程操作一个共享变量时,会使变量发生数据的不完整性(逻辑错误),需要实现线程同步
- 实现线程同步的方案:把修改变量的方法或者块修饰为同步方法或者同步块 synchronized 关键字来修饰
public class Demo9 {
static int tickets = 10;
public static void main(String[] args) {
Saler s1=new Saler();
Saler s2=new Saler();
s1.start();
s2.start();
}
}
class Saler extends Thread{
public synchronized void run(){
while(true){
synchronized(Demo9.class){
if(Demo9.tickets==0){
try {
throw new Exception("没票了");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
Demo9.tickets--;
System.out.println(Thread.currentThread().getName()+"窗口买了一张票,还剩"+Demo9.tickets+"张票");
try {
Thread .sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Demo10 {
/*public static void main(String[] args) {
Shop s1=new Shop();
Shop s2=new Shop();
s1.start();
s2.start();
}
}
class Shop extends Thread{
public void run(){
System.out.println("挑衣服");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(Shop.class){
System.out.println("试衣服");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("试完了");
}*/
public static void main(String[] args) {
Shop shop = new Shop();
Myth t1 = new Myth(shop);
Myth t2 = new Myth(shop);
t1.start();
t2.start();
}}
class Myth extends Thread{
Shop shop;
public Myth(Shop shop){
this.shop=shop;
}
public void run(){
shop.method();
}
}
class Shop {
public void method(){
System.out.println("挑衣服");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(Shop.class){
System.out.println("试衣服");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("试完了");
}
}
2.7 同步线程的通信
wait();//当前线程处于阻塞状态
notify()notifyAll()//唤醒等待的线程
public class Demo8 {
public static void main(String[] args) {
Bank b=new Bank();
Thread t1=new Thread(()->{
b.take(20);
});
Thread t2=new Thread(()->{
b.take(50);
});
Thread t3=new Thread(()->{
b.save(100);
});
t1.start();
t2.start();
t3.start();
}
}
class Bank{
int money=100;
int a=0;
public synchronized void take(int money){
for(int i=1;i<=3;i++){
if(this.money<50){
//当》=50行动
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
a=this.money;
this.money-=money;
System.out.println(Thread.currentThread().getName()+" "+a+"-"+money+"="+this.money);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized void save(int money){
for(int i=1;i<=2;i++){
int b=0;
b=this.money;
this.money+=money;
System.out.println(Thread.currentThread().getName()+" "+b+"+"+money+"="+this.money);
}
notifyAll();//唤醒wait的所有线程
}
}
2.8 线程池
public class Demo11 {
public static void main(String[] args) {
//1.获取线程池
ExecutorService threadPool=Executors.newFixedThreadPool(3);
//2.添加线程到线程池
for(int i=1;i<=6;i++){
Thread t=new Thread(()->{
System.out.println(Thread.currentThread().getName()+":开始执行");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":执行完毕");
});
threadPool.execute(t);//添加线程到线程池
}
//3.关闭线程
threadPool.shutdown();//不关闭正在执行的线程
//threadPool.shutdownNow();//不管线程是否执行完毕,立即停止执行
System.out.println("关闭线程!");
}
}
2.9线程练习
//例题,用来看
public class Demo {
final static Object obj =new Object();//锁
static String name[]=new String[10];
static String sex[]=new String[10];
static int count=0;
static final int SUM=5;
public static void main(String args[]){
Thread thread1=new read();
Thread thread2=new write();
thread1.start();
thread2.start();
}
public static class write extends Thread{
public void run() {
Scanner sc = new Scanner(System.in);
while(count<SUM) {
synchronized (obj) {
if(name[count]!=null) {
try {
obj.wait();
System.out.println("wirte thread wait over");
}catch(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("write thread get obj lock");
System.out.println("请输入第"+count+"个人的姓名:");
name[count] = sc.nextLine();
System.out.println("请输入性别:");
sex[count] = sc.nextLine();
System.out.println("写好了数据"+count);
obj.notify();
System.out.println("write thread notify read one ");
}
}
sc.close();
}
}
public static class read extends Thread{
public void run() {
while(count<SUM) {
synchronized (obj) {
System.out.println("read thread get obj lock");
try {
if(name[count]==null)
obj.wait();
System.out.println("read thread don't wait");
}catch(InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println("姓名:"+name[count]+",性别:"+sex[count]);
Thread.sleep(50);
System.out.println("读好了数据"+count);
count++;
obj.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("read don't have obj lock");
}
}
}
}
//12A 34B --------5152Z
public class Test1 {
public static void main(String[] args) {
Object obj=new Object();
new Thread(new Num(obj)).start();
new Thread(new Zimu(obj)).start();
}
}
class Num implements Runnable{
private Object obj;
public Num(Object obj){
this.obj=obj;
}
@Override
public void run() {
synchronized(obj){
for(int i=1;i<53;i++){
if(i>1&&i%2!=0){
System.out.println(" ");
}
System.out.print(i);
obj.notify();//通知等的线程,但是要执行完当前代码块的代码
if(i%2==0){
try {
obj.wait();//线程挂起,让出CPU资源
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
class Zimu implements Runnable{
private Object obj;
public Zimu(Object obj){
this.obj=obj;
}
@Override
public void run() {
synchronized(obj){
for(char i='A';i<='Z';i++){
System.out.print(i);
obj.notify();//通知等的线程,但是要执行完当前代码块的代码
if(i<'Z'){
try {
obj.wait();//线程挂起,让出CPU资源
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
public class test1 {
static final Object o=new Object();//锁,保证两个线程用同一锁进行资源的使用与释放的调度
public static void main(String[] args) {
Thread thread1=new Number();
Thread thread2=new Zimu();
thread1.start();
thread2.start();
}
public static class Number extends Thread{
public void run(){
for(int i=1;i<52;i=i+2){
synchronized (o){
int x=i+1;
System.out.print(i+""+x);
o.notifyAll();
try {
o.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public static class Zimu extends Thread{
public void run(){
synchronized (o){
for(char i='A';i<='Z';i++){
if(i=='Z'){
System.out.print(i);
o.notify();
}else{
System.out.print(i);
System.out.println("");
o.notifyAll();
try {
o.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}
/*
* 0:1,2,3,4,5,
* 1:6,7,8,9,10,
* 2:11,12,13,14,15,
* 0:16,17,18,19,20,
* 1:21,22,23,24,25,
*/
public class Test2 {
public static void main(String[] args) {
Object obj=new Object();
new Thread(new Number(obj,0)).start();
new Thread(new Number(obj,1)).start();
new Thread(new Number(obj,2)).start();
}
}
class Number implements Runnable{
Object obj;
int id;
static int num=1;
public Number(Object obj,int id){
this.obj=obj;
this.id=id;
}
@Override
public void run() {
synchronized(obj){
while(num<=75){
if(num/5%3==id){
System.out.print(id+": ");
for(int i=1;i<=5;i++){
System.out.print(num++ +",");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println();
obj.notifyAll();
}else{
try {
obj.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}