目录
一、线程的介绍
二、线程的使用
(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--;
}
}
}
}
}