文章目录
程序(program)
进程
线程
java程序来显示电脑有多少个CPU
package 绘图;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-24
* @Description: no
* @Version: 1.0
*/
public class demo02 {
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
//获取当前电脑cpu数量
System.out.println(runtime.availableProcessors()); //16
}
}
线程基本使用
简单案例
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-24
* @Description: no
* @Version: 1.0
*/
public class demo01 {
public static void main(String[] args) throws Exception {
//创建Cat对象,可以当作线程使用
Cat cat = new Cat();
cat.start();// 启动线程------》最终会执行cat的run方法
// cat.run(); 如果直接这样写,就是一个普通的方法,线程名字还是main,并没有真正启动一个线程,就会把run方法执行完毕,才向下执行
//当main线程启动一个子线程 Thread-0,主线程不会阻塞,会继续执行。
//底层机制
// public void start() {
// synchronized (this) {
// // zero status corresponds to state "NEW".
// if (holder.threadStatus != 0)
// throw new IllegalThreadStateException();
// start0();
// }
// start0()是本地方法,是JVM调用,底层是c/c++实现
System.out.println("主线程继续执行"+Thread.currentThread().getName()); //main
for (int i = 0; i < 10; i++) {
System.out.println("主线程 i = "+i);
Thread.sleep(1000);
}
}
}
//1.当一个类继承了Thread类,该类就可以当作线程使用
//2. 我们会重写run方法
//3. run Thread 类实现了Runnable接口 的run方法
class Cat extends Thread{
@Override
public void run() {
int times = 0;//重写run方法,写上自己的业务逻辑
while (true) {
// 该线程每隔1秒,在控制台输出“爱你哦,小韩!”
System.out.println("爱你哦,小韩!"+(++times)+"线程名="+Thread.currentThread().getName());
// 让该线程休眠1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (times == 8) { //线程退出
break;
}
}
}
}
Runnable创建线程
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-24
* @Description: 通过实现接口Runnable来开发线程
* @Version: 1.0
*/
public class demo02 {
public static void main(String[] args) {
Dog dog = new Dog();
// dog.start(); //错误,没有该方法
//创建了Thread对象,把dog对象(实现了Runnable接口),放入
//这里使用了静态代理的设计模式
Thread thread = new Thread(dog);
thread.start();
}
}
class Dog implements Runnable{ //通过实现Runnable 接口来开发线程
int count = 0;
@Override
public void run() {
while(true){
System.out.println("小狗汪汪叫"+(++count)+Thread.currentThread().getName());
//休眠1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(count == 10){
break;
}
}
}
}
看一个线程代理类,来模拟一个极简的Thread类
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-24
* @Description: 通过实现接口Runnable来开发线程
* @Version: 1.0
*/
public class demo02 {
public static void main(String[] args) {
Tiger tiger = new Tiger(); //实现了Runnbale
ThreadProxy threadProxy = new ThreadProxy(tiger);
threadProxy.start();
//控制台输出:老虎嗷嗷叫!
}
}
class Animal{}
class Tiger extends Animal implements Runnable{
@Override
public void run() {
System.out.println("老虎嗷嗷叫!");
}
}
//线程代理类,模拟了一个极简的Thread类
class ThreadProxy implements Runnable {
private Runnable target = null;
@Override
public void run() {
if (target != null) {
target.run(); //动态绑定 运行类型是传进来的Tiger
}
}
public ThreadProxy(Runnable target) { //一般将实现了runnable接口的线程类传给 target,通过构造器传过去的,然后其它主要特点就是动态绑定了
this.target = target;
}
public void start(){
start0();
}
public void start0(){
run();
}
}
多线程
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: main线程启动两个子线程
* @Version: 1.0
*/
public class demo03 {
public static void main(String[] args) {
T1 t1 = new T1();
T2 t2 = new T2();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
}
}
class T1 implements Runnable{
int count = 0;
@Override
public void run() {
while (true) {
System.out.println("hello word " + (++count));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 50) {
break;
}
}
}
}
class T2 implements Runnable{
int count = 0;
@Override
public void run() {
while (true) {
System.out.println("hi " + (++count));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 60) {
break;
}
}
}
}
继承Thread vs实现Runnable的区别
线程终止
基本说明
- 当线程完成任务后,会自动退出
- 还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式
简单案例
要求在main线程中去终止线程t
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: no
* @Version: 1.0
*/
public class demo06 {
public static void main(String[] args) {
T t = new T();
t.start();
//如果需要main线程,控制T1线程的终止,只需修改loop
//让t1 退出run方法,从而终止t1线程--->通知方式
try {
System.out.println("主线程休眠10秒");
Thread.sleep(10000); //主线程休眠10秒
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
t.setLoop(false);
}
}
class T extends Thread {
private int count = 0;
private boolean loop = true; //设置控制变量
@Override
public void run() {
while (loop) {
try {
Thread.sleep(50); //50ms
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("T 运行中"+(++count));
}
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}
线程常用方法
注意事项和细节
简单案例
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: no
* @Version: 1.0
*/
public class demo07 {
public static void main(String[] args) throws Exception {
T12 t12 = new T12();
t12.setName("老韩"); //给线程设置名字
t12.setPriority(Thread.MAX_PRIORITY); //设置线程为最小优先级
t12.start();
//让主线程打印5 hi,然后我就中断子线程的休眠
for (int i = 0; i < 5; i++) {
Thread.sleep(1000);
System.out.println("hi"+i);
}
System.out.println(t12.getName()+"线程的优先级="+t12.getPriority());
t12.interrupt(); //中断 当执行到这里,就会中断t线程的休眠
}
}
class T12 extends Thread { //自定义线程类
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"吃包子~~~~~~~~"+i);
}
try {
System.out.println(Thread.currentThread().getName()+"休眠中~~~~~~~~");
Thread.sleep(20000);
} catch (InterruptedException e) {
//当该线程执行到一个interrupt 方法时,就会catch 一个异常,可以加入自己的业务代码
System.out.println(Thread.currentThread().getName()+"被interrupt了");
}
}
}
join()和yield()方法
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: no
* @Version: 1.0
*/
public class demo07 {
public static void main(String[] args) throws Exception {
T12 t12 = new T12();
t12.start();
for (int i = 0; i < 20; i++) {
Thread.sleep(1000);
System.out.println("主线程吃了"+i+"个包子");
if(i == 5){
System.out.println("主线程让子线程先吃");
//线程插队
// t12.join(); //相当于当让t2先执行完毕
Thread.yield(); //主线程礼让 包子资源丰富,资源不紧缺,礼让不成功
System.out.println("子线程吃完,主线程接着吃");
}
}
}
}
class T12 extends Thread { //自定义线程类
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("子线程吃了"+i+"个包子");
}
}
}
用户线程和守护线程
-
用户线程
也叫做工作线程,当线程的任务执行完或通知方式结束
-
守护线程:一般是为了工作线程服务的,当所有的用户线程结束,守护线程自动结束
-
常见的守护线程:垃圾回收机制
如何将一个线程设置成守护线程
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: no
* @Version: 1.0
*/
public class demo09 {
public static void main(String[] args) throws Exception {
MyDaemon myDaemon = new MyDaemon();
//我们希望主线程结束,子线程自动退出,只需将子线程设置为守护线程
myDaemon.setDaemon(true); //先设置,再启动
myDaemon.start();
for (int i = 1; i <= 10; i++) {
System.out.println("宝强在辛苦工作。。。");
Thread.sleep(1000);
}
}
}
class MyDaemon extends Thread {
@Override
public void run() {
for(;;){
try {
Thread.sleep(1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("马蓉和宋哲在愉快的聊天......");
}
}
}
线程的生命周期
JDK 中用 Thread.State 枚举表示了线程的几种状态
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: no
* @Version: 1.0
*/
public class demo10 {
public static void main(String[] args) throws Exception {
T10 t10 = new T10();
System.out.println(t10.getName() + "状态" + t10.getState());
t10.start();
while (Thread.State.TERMINATED != t10.getState()) { //只要线程还没终止,就打印出线程目前的状态
System.out.println(t10.getName() + "状态" + t10.getState() );
Thread.sleep(1000);
}
System.out.println(t10.getName() + "状态" + t10.getState());
}
}
class T10 extends Thread {
@Override
public void run() {
while (true) {
for (int i = 0; i < 10; i++) {
System.out.println("hi "+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
}
}
}
线程同步机制(Synchronized)
案例:三个窗口,出售100张票
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: no
* @Version: 1.0
*/
public class demo05 {
public static void main(String[] args) {
SellTickets3 sellTicket = new SellTickets3();
Thread thread1 = new Thread(sellTicket);
Thread thread2 = new Thread(sellTicket);
Thread thread3 = new Thread(sellTicket);
thread1.start();
thread2.start();
thread3.start();
}
}
class SellTickets3 implements Runnable{
private int tickes = 100; //多个线程共享tickes
private boolean loop =true;
public synchronized void sell(){ 同步方法,在同一时刻,只能有一个线程来执行m方法
if (tickes == 0) {
System.out.println("售票结束。。。");
loop = false;
return;
}
System.out.println("窗口"+Thread.currentThread().getName()+"售出一张票,剩余票数"+(--tickes));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
public void run() {
while (loop) {
sell();
}
}
}
分析同步原理
锁,在对象上
互斥锁
基本介绍
注意事项
简单案例
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: no
* @Version: 1.0
*/
public class demo05 {
public static void main(String[] args) {
SellTickets3 sellTicket = new SellTickets3();
Thread thread1 = new Thread(sellTicket);
Thread thread2 = new Thread(sellTicket);
Thread thread3 = new Thread(sellTicket);
thread1.start();
thread2.start();
thread3.start();
}
}
class SellTickets3 implements Runnable{
private int tickes = 100; //多个线程共享tickes
private boolean loop =true;
Object object = new Object();
//同步方法(静态的)的锁为当前类本身
//解读:
//1. public synchronized static void m1() 锁是加在SellTickets3.class 上的
//2. 如果在静态方法中,要实现一个同步代码块
/*synchronized (SellTickets3.class){
System.out.println("m2");
}*/
public synchronized static void m1(){}
public static void m2(){
synchronized (SellTickets3.class){
System.out.println("m2");
}
}
//说明:
// 1. public synchronized void sell() 就是一个同步方法
// 2. 这时候,锁在this对象上
// 3. 也可以在代码块上写synchronized,同步代码块,互斥锁还是在this对象上
public /*synchronized8*/ void sell(){ 同步方法,在同一时刻,只能有一个线程来执行m方法
synchronized (/*this*/ object){
if (tickes <= 0) {
System.out.println("售票结束。。。");
loop = false;
return;
}
System.out.println("窗口"+Thread.currentThread().getName()+"售出一张票,剩余票数"+(--tickes));
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void run() {
while (loop) {
sell();
}
}
}
线程死锁
基本介绍
多个线程都占用了对方锁的资源,但不肯相让,导致了死锁。在编程时,要避免死锁的发生。
应用案例
妈妈:你先完成作业,才让你玩手机
小明:你让我玩手机,我才写作业
package 线程;
/**
* @Author: 韩如意
* @CreateTime: 2025-02-25
* @Description: 模拟死锁
* @Version: 1.0
*/
public class demo12 {
public static void main(String[] args) {
//模拟死锁现象
DeadLockDemo A = new DeadLockDemo(true);
DeadLockDemo B = new DeadLockDemo(false);
A.start();
B.start();
/*控制台卡在这里了:
Thread-1进入3
Thread-0进入1*/
}
}
//线程
class DeadLockDemo extends Thread {
static Object o1 = new Object(); //保证多线程,共享一个对象,这里使用static
static Object o2 = new Object();
boolean flag;
public DeadLockDemo(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
//下面逻辑分析
//1. 如果flag为T,线程A就会先得到/持有 o1对象,然后尝试去获取噢对象锁
//2. 如果线程A得不到o2对象锁,就会Blocked
//3. 如果Flag为F,线程B就会得到/持有 o2对象锁,然后尝试去获取o1对象锁
//4. 如果线程B 得不到o1 对象锁,就会Blocked
//
if(flag){
synchronized (o1) { //对象互斥锁,下面就是我们的同步代码
System.out.println(Thread.currentThread().getName()+"进入1");
synchronized (o2) { //这里获取o1对象的监视权
System.out.println(Thread.currentThread().getName()+"进入2");
}
}
}else {
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入3");
synchronized (o1) { //这里获取o2对象的监视权
System.out.println(Thread.currentThread().getName()+"进入4");
}
}
}
}
}