Java线程学习总结
今天把Java多线程学习了一下,作如下总结
进程与线程
进程是程序关于某个数据集合的一次执行过程
线程是操作系统能够运算调度的最小单位,是进程中单一顺序的控制流
一个进程可以并发执行多个线程,进程是线程的容器
例如:电脑QQ,QQ是进程,发送消息,QQ空间就是线程
单线程
单线程,就是程序执行时,进程中的线程顺序是连续的
package ThreadExample;/*** @author cxw* @date 2022/4/30*/public class Singal_ThreadExample {//单线程演示//单线程,程序执行时,进程中的线程顺序是连续的public static void main(String[] args) {MyThread m1 = new MyThread("MyThread1");MyThread m2 = new MyThread("MyTHread2");m1.run();m2.run();//单线程的限制//m2调用run()方法,要等m1调用完了之后才可以继续调用//多线程可以实现上述结果交叉输出 多线程即进程可以并发执行//实际上所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。}
}//单线程
class MyThread {String str;public MyThread(String str) {this.str = str;}void run() {for (int i = 0; i < 3; i++) {System.out.println("输入参数是: " + str);}}
}
多线程
多线程可以使单个程序内部在同一时刻执行多个代码段,完成不同的任务。一个复杂的任务可以分解为多个子任务交予线程执行,实现异步执行环境
多线程可以实现上述结果交叉输出 多线程即进程可以并发执行
例如,浏览器就是一个多线程的例子,可以浏览网页时同时播放声音和动画
多线程的实现方法
常用的两个,一是创建线程子类,继承Thread类;二是在定义的类中实现Runnable接口
创建Thread类的子类
创建一个类,继承Thread类并且重写其中的run()方法
package ThreadExample;/*** @author cxw* @date 2022/4/30*/public class MyThreadExample {//创建Thread类的子类来实现多线程static class Thread1 extends Thread {private String str = null;public Thread1(String str) {this.str = str;}//重写Thread中的run()方法public void run() {for (int i = 0; i < 3; i++) {System.out.println("你输入的是:" + str);try {//sleep(long millis): 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)//Thread.sleep()方法调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留出一定时间给其他线程执行的机会。Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {Thread1 t1 = new Thread1("Thread1");Thread1 t2 = new Thread1("===============");Thread1 t3 = new Thread1("Thread2");t1.start();t2.start();t3.start();/*你输入的是:Thread1你输入的是:Thread2你输入的是:===============你输入的是:===============你输入的是:Thread1你输入的是:Thread2你输入的是:Thread1你输入的是:===============你输入的是:Thread2*/}
}
实现Runnable接口
Java不支持多线程,如果要继承Thread后就无法继承其他类,但是可以实现Runnable接口并且重写run()方法实现多线程
package ThreadExample;/*** @author cxw* @date 2022/4/30*/public class RunnableExample {//实现Runnablestatic class Mythread implements Runnable {private String str;public Mythread(String str) {this.str = str;}//重写run()方法@Overridepublic void run() {for (int i = 0; i < 3; i++) {System.out.println("你输入的是:" + str);try {//Thread.sleep()方法调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留出一定时间给其他线程执行的机会。Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {Mythread t1 = new Mythread("MyThread1");Mythread t2 = new Mythread("MyThread2");Mythread t3 = new Mythread("============");//将目标对象传递给Thread实例Thread thread1 = new Thread(t1);Thread thread2 = new Thread(t2);Thread thread3 = new Thread(t3);thread1.start();thread2.start();thread3.start();}
}
实现多线程分别打印0~99的数字的功能
实现多线程分别打印0~99的数字的功能
package ThreadExample.Practice;/*** @author cxw* @date 2022/4/30*/public class Practice1 {static class MyThread extends Thread {private int num;public MyThread(int num) {this.num = num;}//重写Thread中的run()方法public void run() {//for (int i = 0; i < 100; i++) {System.out.println("num: " + num);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// }}}public static void main(String[] args) {for (int i = 0; i < 100; i++) {MyThread t1 = new MyThread(i);t1.start();}}
}
Runnable接口和Thread类的区别
两种方法都要执行start()方法来为线程分配系统资源,调度线程并且执行线程run()方法
当一个线程已经继承另一个类时,就应该使用Runnable接口来实现多线程
多线程的同步
如果一个程序激活了多个线程,并且多个线程共享同一资源,可能会发生冲突。这个时候就要使用进程的同步机制来解决
线程同步指的是通过特定的同步机制来控制多线程间的执行顺序,即使多个线程按照预定的先后次序执行
synchronized关键字
synchronized 关键字可以修饰方法或者代码块,相当于给修饰的方法或者代码块上锁,有效防止资源冲突
package ThreadExample;/*** @author cxw* @date 2022/4/30*/public class SameThread {//线程同步问题public static int count = 10;//synchronized 关键字可以修饰方法或者代码块,相当于给修饰的方法或者代码块上锁,有效防止资源冲突public static synchronized int buyTicket() {if (count <= 0) {return -1; //无票}count--;System.out.println("剩余票数: " + count);return count;}public static void main(String[] args) {for (int i = 0; i < 15; i++) {new Thread() {public void run() {SameThread.buyTicket();}}.start();}}
}/* 未加同步锁
剩余票数: 3
剩余票数: 1
剩余票数: 9
剩余票数: 7
剩余票数: 2
剩余票数: 6
剩余票数: 8
剩余票数: 5
剩余票数: 0
剩余票数: 4*//*
加了同步锁
剩余票数: 9
剩余票数: 8
剩余票数: 7
剩余票数: 6
剩余票数: 5
剩余票数: 4
剩余票数: 3
剩余票数: 2
剩余票数: 1
剩余票数: 0*/
同步锁的例题
三个窗口同时售卖20张票
多线程同步锁的应用 三个窗口同时售卖20张票
package ThreadExample.PracticeExample;/*** @author cxw* @date 2022/4/30*/public class Example1 {//多线程同步锁的应用 三个窗口同时售卖20张票static class Sation extends Thread {public Sation(String name) {super(name);}static int count = 20; //票数static Object object = "aa"; //创建一个同步锁 静态的钥匙//重写run方法public void run() {while (count > 0) {//使用一个锁, // 进去的人会把钥匙拿在手上,出来后才把钥匙拿让出来synchronized (object) {if (count > 0) {System.out.println(getName() + "卖出了第 " + count + "张票!");count--;} else {System.out.println("票卖完了!");}}try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}public static void main(String[] args) {Sation s1 = new Sation("站台1");Sation s2 = new Sation("站台2");Sation s3 = new Sation("站台3");s1.start();s2.start();s3.start();}
}/*
运行结果
站台1卖出了第 20张票!
站台3卖出了第 19张票!
站台2卖出了第 18张票!
站台1卖出了第 17张票!
站台3卖出了第 16张票!
站台2卖出了第 15张票!
站台1卖出了第 14张票!
站台3卖出了第 13张票!
站台2卖出了第 12张票!
站台1卖出了第 11张票!
站台3卖出了第 10张票!
站台2卖出了第 9张票!
站台1卖出了第 8张票!
站台3卖出了第 7张票!
站台2卖出了第 6张票!
站台1卖出了第 5张票!
站台3卖出了第 4张票!
站台2卖出了第 3张票!
站台1卖出了第 2张票!
站台3卖出了第 1张票!*/
银行取钱1
两个人AB通过一个账户A在柜台取钱和B在ATM机取钱!
package ThreadExample.PracticeExample;
/*** @author cxw* @date 2022/4/30*/import java.util.Objects;public class Example2 {//两个人AB通过一个账户A在柜台取钱和B在ATM机取钱!public static void main(String[] args) {Bank bank = new Bank();PersonA personA = new PersonA(bank, "ATM", "小明");PersonB personB = new PersonB(bank, "Counter", "小白");personA.start();personB.start();}}//银行类
class Bank {//账户的金额为1000static double money = 1000;//在柜台取钱public void Counter(double money) {this.money -= money;System.out.println("柜台取钱 " + money + "还剩 " + this.money);}//在ATM机取钱public void ATM(double money) {this.money -= money;System.out.println("ATM取钱 " + money + "还剩 " + this.money);}//提供一个对外取款的途径public synchronized void OutMoney(double money, String mode) throws Exception {if (money > this.money) {//检验余额是否充足throw new Exception("取款金额" + money + ",余额只剩" + this.money + ",取款失败!");}if (Objects.equals(mode, "ATM")) {ATM(money);} else {Counter(money);}}
}//创建一个人类,模拟取钱 继承自Thread类
class PersonA extends Thread {//哪个银行private Bank bank;//何种方式private String mode;//姓名private String name;public PersonA(Bank bank, String mode, String name) {this.bank = bank;this.mode = mode;this.name = name;}@Overridepublic void run() {while (bank.money >= 100) {try {bank.OutMoney(100, mode);} catch (Exception e) {e.printStackTrace();}try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}class PersonB extends Thread {//哪个银行private Bank bank;//何种方式private String mode;//姓名private String name;public PersonB(Bank bank, String mode, String name) {this.bank = bank;this.mode = mode;this.name = name;}@Overridepublic void run() {while (bank.money >= 200) {try {bank.OutMoney(200, mode);} catch (Exception e) {e.printStackTrace();}try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
银行取钱2
编写一个模拟银行存款的程序。假设有两个储户都去银行往同一账户存款,一次存100,每次存3次。要求储户每存一次前,账户余额增加100,并在控制台输出当前账户的余额。
package ThreadExample.Practice;/*** @author cxw* @date 2022/4/30*/public class Practice2 {public static void main(String[] args) {//进程同步锁的使用Bank bank = new Bank();Person a = new Person(bank);Person b = new Person(bank);Person c = new Person(bank);Thread t1 = new Thread(a);Thread t2 = new Thread(b);Thread t3 = new Thread(c);t1.start();t2.start();t3.start();}
}//银行类
class Bank {//账户的初始金额为1000static double money = 1000;//存钱的方法public void SaveMoney(double getMoney) {money += getMoney;System.out.println("柜台存钱 " + getMoney + ",总金额为 " + money);}
}//创建一个存钱的人类,模拟存钱
class Person implements Runnable {Bank bank;static Object object = "aa"; //创建一个同步锁public Person(Bank bank) {this.bank = bank;}//重写run()方法@Overridepublic void run() {//存到3000块停止存钱while (bank.money < 3000) {//同步锁 金额随存钱次数的增加而不同步改变synchronized (object) {try {bank.SaveMoney(100);} catch (Exception e) {e.printStackTrace();}}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
欢迎大家指正,over
作者:爱吃水果的cc