Java---线程详解

目录

一、线程的介绍

二、线程的使用

(1)多线程的实现

1:继承Thread类

2:实现Runnable接口

(2)设置和获取线程名称

1:继承Thread类

2:实现Runnable接口

(3)线程的优先级

(4)线程的控制

1:sleep方法

2:join方法

3:setDaemon方法

三、线程安全 


一、线程的介绍

线程是进程中的单个顺序控制流,是一条执行路径。说得简单点吧,比如说扫雷这个游戏,有一个线程是扫雷,有一个程序是计时,可这个计时并不是直接计时,它是等开始扫雷时才进行,其实我说的意思就是计时是一个程序,扫雷是一个程序,但他们是单独的程序,他们每一个程序其实就是一个线程。(个人理解的补充:在后面他执行的时候其实就是要拿到CPU的执行权,但一般电脑都是只有一个CPU吧,多个线程去抢,谁抢到了,就执行哪个线程)
单线程:一个进程中如果只有一条执行路径,就是单线程程序
多线程:一个进程中如果有多条执行路径,则称为多线程程序

 

二、线程的使用

(1)多线程的实现

多线程的实现方式有两种
1:继承Thread类
2:实现Runnable接口


1:继承Thread类(要重写Thread类中的run方法,并使用start方法启动线程)

//这是继承类
public class mythread extends Thread{
   public void run() {
	   for(int i=1;i<20;i++) {
		   System.out.println(i);
	   }
   }
}

//这是测试类
public class test {
   public static void main(String[] args) throws UnknownHostException {
	  mythread m1=new mythread();
	  mythread m2=new mythread();
	  m1.start();
	  m2.start();
   }
}

2:实现Runnable接口


public class mythread implements Runnable{
   public void run() {
	   for(int i=1;i<20;i++) {
		   System.out.println(i);
	   }
   }
}

//测试类

public class test {
   public static void main(String[] args) throws UnknownHostException {
	    mythread m=new mythread();
	    Thread m1=new Thread(m);
	    Thread m2=new Thread(m);
	    
	    m1.start();
	    m2.start();
   }
}

(2)设置和获取线程名称

1:继承Thread类


public class thread extends Thread{
   public void run() {
	   for(int i=0;i<10;i++) {
		   System.out.println(Thread.currentThread().getName()+":"+i);
	   }
   }
}

public class test {
   public static void main(String[] args) throws UnknownHostException {
	  thread m1=new thread();
	  thread m2=new thread();
	  m1.setName("ioi");
	  m2.setName("opopop");
	  
	  m1.start();
	  m2.start();
	  
   }
}

 

2:实现Runnable接口

public class mythread implements Runnable{
   public void run() {
	   for(int i=1;i<20;i++) {
		   System.out.println(Thread.currentThread().getName()+":"+i);
		   
	   }
   }
}


public class test {
   public static void main(String[] args) throws UnknownHostException {
	   mythread m=new mythread();
	   Thread m1=new Thread(m,"高铁");
	   Thread m2=new Thread(m,"飞机");
	   
	   System.out.println("第一="+m1.getName());
	   System.out.println("第二="+m2.getName());
	   m1.start();
	   m2.start();
	   
   }
}

(3)线程的优先级

Java使用的线程调度是抢占式调度模型,抢占式调度模型就是优先让优先级高的使用CPU,如果线程的优先级相同,那么随机一个,优先级高的线程获取的CPU时间片相对多一些。

假如计算机只有一个CPU,那么CPU在某一时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。
所以说多线程程序的执行是有随机性的,因为谁抢到CPU的使用权是不一定的。

注意哈,优先级高并不一定是它先执行,它只是加大了可以拿到CPU权限的概率而已


Thread类中设置和获取线程优先级的方法
(1)public final int getPriority()   返回此线程的优先级
(2)public final void setPriority()  更改此线程的优先级
public class test {
   public static void main(String[] args) throws UnknownHostException {
	  thread m1=new thread();
	  thread m2=new thread();
	  
	  m1.setName("高铁");
	  m2.setName("飞机");
	  m1.setPriority(3);
	  m2.setPriority(8);
	  System.out.println("第一个线程的="+m1.getPriority());
	  System.out.println("第二个线程="+m2.getPriority());
	  m1.start();
	  m2.start();
   }
}

(4)线程的控制

1:sleep方法

public class thread extends Thread{
   public void run() {
	   for(int i=0;i<10;i++) {
		   System.out.println(Thread.currentThread().getName()+":"+i);
		   try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	   }
   }
}
//test类正常使用就行

2:join方法

public class test {
   public static void main(String[] args) throws UnknownHostException {
	  thread m1=new thread();
	  thread m2=new thread();
	  thread m3=new thread();
	  
	  m1.setName("高铁");
	  m2.setName("飞机");
	  m3.setName("公交");
	  
	  
	  m1.start();
//等m1这个线程死亡之后,后面的线程开始抢夺CPU的执行权限
	  try {
		m1.join();
	} catch (InterruptedException e) {
		// TODO 自动生成的 catch 块
		e.printStackTrace();
	}
	  m2.start();
	  m3.start();
   }
}

 

3:setDaemon方法

该方法用来开启守护线程,守护线程的作用就是和主线程同生共死,但是主线程结束之后,守护线程不会立即死亡,而是会挣扎几下才会死亡哦

public class test {
   public static void main(String[] args) throws UnknownHostException {
	  thread m1=new thread();
	  thread m2=new thread();
	  
	  m1.setName("高铁");
	  m2.setName("飞机");
	  
	  Thread.currentThread().setName("我是主线程");
	  m1.setDaemon(true);
	  m2.setDaemon(true);
	  
	  m1.start();
	  m2.start();
	  for(int i=0;i<10;i++) {
		  System.out.println(Thread.currentThread().getName()+":"+i);
	  }
   }
}

三、线程安全 

假如给你一个案列:A,B,C三个窗口卖票,票数是100张,每次顾客来买票时,票数减一,并且在控制台输出是哪一个窗口卖出的票,和当前正在出售第几张票。

如果按照正常使用线程解决该题的话,也就是如下的代码:

public class mythread implements Runnable{
	private int ticket=100;
	@Override
	public void run() {
		// TODO 自动生成的方法存根
		while(true) {
			if(ticket>0) {
				//票数大于0,,也就是有票的情况
				try {
					Thread.sleep(100);//休眠0.1秒
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
				ticket--;
			}
		}
	}
}
public class test {
   public static void main(String[] args) throws UnknownHostException {
	  mythread m=new mythread();
	  Thread s1=new Thread(m,"A");
	  Thread s2=new Thread(m,"B");
	  Thread s3=new Thread(m,"C");
	  
	  s1.start();
	  s2.start();
	  s3.start();
   }
}

 看到上面你会发现怎么出现了-1呢?

在其中假如a抢到了CPU的执行权限进入if分支,后面遇到休眠。在休眠
的这段时间内b又抢到了CPU的执行权限进入分支,进入休眠,假如这时候
a醒来后执行操作,输出,并将票数-1,假如此时票数已经是0了,后面判断
票数自然无法进入if分支了,但是如果,之前就在if分支里但是是在休眠就可以
再次进行输出和票数减一了

那么该如何解决呢?这时候就需要用到同步代码块了

public class mythread implements Runnable{

	private int ticket=100;
	private Object obj=new Object();
	@Override
	public void run() {
		// TODO 自动生成的方法存根
		
		while(true) {
		  synchronized (obj) {//同一把锁
			if(ticket>0) {
				//票数大于0,,也就是有票的情况
				
				try {
					Thread.sleep(100);//休眠0.1秒
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"正在出售第"+ticket+"张票");
				ticket--;
			}
		}
		}
			
	}
   
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜到极致就是渣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值