一、线程基础知识
1、什么是线程
官方一点的解释:进程是资源分配的最小单位,线程是CPU调度的最小单位。
即进程可以理解为一个正在运行的程序,而线程就是进程中去各个模块执行任务的线程。
2、线程的两种常见的开启方法
package thread;
public class Demo02 {
public static void main(String[] args) {
//通过继承Thread类开启线程
Thread t1 = new Thread01();
t1.start();
System.out.println("********分隔线**********");
//通过实现Runnable接口开启线程
Thread02 thread02 = new Thread02();
Thread t2 = new Thread(thread02);
t2.start();
}
}
class Thread01 extends Thread {
@Override
public void run() {
System.out.println("通过继承Thread类实开启线程!");
}
}
class Thread02 implements Runnable {
@Override
public void run() {
System.out.println("通过实现Runnable接口开启线程!");
}
}
>但是java真的可以开启线程吗?
我们可以点击看一下start()方法源码:
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
* 如果是0,则表示该线程是新创建的
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
//底层其实使用的是c++语言编写的启动方法。java是无法直接操作硬件的
private native void start0();
3、多线程生命周期
简单点说,线程的生命周期有五个状态:新建->就绪->运行->阻塞->死亡
4、关于并行和并发
并行: CPU多核,多个线程可以一起执行,以线程池为例子。
并发: CPU单核,多个线程快速交替。
二、常用的多线程方法
//获取当前线程对象
Thread.currentThread()
//设置和获得优先级,优先级越高,不一定就是先运行,看cpu心情,只是相对概率大一些
setPriority()
getPriority()
//礼让线程,只是让大家重回起跑线上,至于下个线程先启用谁,看cpu心情
yield()
//判断线程是否存活
isAlive()
//合并线程
jion()
//等待线程
wait()
//唤醒一个线程和所有线程
notify()
notifyAll()
//线程睡眠
sleep()
//线程中断
interrupt()
用几个案例体会一下:
package thread;
//测试优先级
public class Demo03 {
public static void main(String[] args) {
//开启三个线程
Thread t1 = new Thread(new ThreadTest1(),"A");
Thread t2 = new Thread(new ThreadTest1(),"B");
Thread t3 = new Thread(new ThreadTest1(),"C");
//设置优先级
t1.setPriority(1);
t2.setPriority(2);
t3.setPriority(3);
//运行
t1.start();
t2.start();
t3.start();
}
}
class ThreadTest1 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"正在运行!");
}
}
出现的结果:
B正在运行!
C正在运行!
A正在运行!
理想中的结果:
C正在运行!
B正在运行!
A正在运行!扫描二维码关注公众号,回复: 11339898 查看本文章
再来一个龟兔赛跑小实验:
package thread;
public class Race {
public static void main(String[] args) {
Run r = new Run();
new Thread(r,"兔子").start();
new Thread(r,"乌龟").start();
}
}
class Run implements Runnable {
private static String WINNER;
@Override
public void run() {
for (int i = 0; i <=15000 ; i++) {
if(isGameOver(i)) {
break;
}
//如果当前线程是兔子的话,它每次可以多跑一步,兔子的速度要快。
if (Thread.currentThread().getName().equals("兔子")) {
System.out.println(Thread.currentThread().getName()+"跑了"+i+++"步");
}else {
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
}
public boolean isGameOver(int i) {
if (WINNER!=null){
return true;
}else {
if (i>=15000) {
WINNER = Thread.currentThread().getName();
System.out.println("winner is"+WINNER);
return true;
}
return false;
}
}
}
经过测试
乌龟跑了8898步
乌龟跑了8899步
winner is兔子
在步数范围较大时,基本都是兔子赢了
但是我们知道龟兔赛跑中,兔子在中途睡了一觉。所以我们增加一个方法
package thread;
public class Race {
public static void main(String[] args) {
Run r = new Run();
new Thread(r,"兔子").start();
new Thread(r,"乌龟").start();
}
}
class Run implements Runnable {
private static String WINNER;
@Override
public void run() {
for (int i = 0; i <=15000 ; i++) {
if(isGameOver(i)) {
break;
}
//如果当前线程是兔子的话,它每次可以多跑一步
if (Thread.currentThread().getName().equals("兔子")) {
System.out.println(Thread.currentThread().getName()+"跑了"+i+++"步");
try {
//兔子睡了一个大懒觉
Thread.sleep(1000*5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
}
public boolean isGameOver(int i) {
if (WINNER!=null){
return true;
}else {
if (i>=15000) {
WINNER = Thread.currentThread().getName();
System.out.println("winner is"+WINNER);
return true;
}
return false;
}
}
}
经过测试
乌龟跑了14998步
乌龟跑了14999步
winner is乌龟
在龟兔赛跑中,我们让兔子进行等待睡眠调用的是sleep方法,那么,wait()方法的作用时什么呢?
字面意思,就是线程进入等待,特点就是wait()方法会释放一把锁,同时线程进入阻塞状态
底层实现:
/**
*This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor. wait方法一般都是和notify和notifyAll配合使用。
*/
//先是调用了一个无参方法
public final void wait() throws InterruptedException {
//里面调用了一个有参方法,设置参数为0
wait(0);
}
//有参方法,是用C语言编写,底层实现就看不到了。
// @param timeout the maximum time to wait in milliseconds.最大的等待时长
public final native void wait(long timeout) throws InterruptedException;
那么。notify和notifyAll有什么区别呢?
//两个都是C语言写的方法
//Wakes up a single thread that is waiting on this object's monitor.
//唤醒一个单线程,线程是随机抽取的,看CPU心情
public final native void notify();
//Wakes up all threads that are waiting on this object's monitor.
//唤醒所有被监控的线程
public final native void notifyAll();
好了,多线程基本的概念和方法使用大体上就是如此。不知道您这边是否有所收获呢?