线程和多线程的概念及拓展
线程:线程是进程的细化,是程序内部的一条执行路径。
多线程:一个进程在同一时间内进行多个线程,操作系统能同时运行多个任务。
cpu调度:分时调度:所有线程轮流使用cpu的使用权,并且平均分配每个线程占用cpu的时间。 抢占式调度:让优先级高的线程以较大概率获得cpu的使用权,如果优先级相同,那么会随机选择一个线程获得cpu的使用权。【java使用的就是抢占式调度】【线程是cpu调度的最小单位】
线程的创建方式
一,继承java.lang.Thread类
js
代码如下
public class ThreadTest01 extends Thread{
public ThreadTest01(String name) {
super(name);
}
public void run(){
}
js
主线程
public class Test {
public static void main(String[] args) {
ThreadTest01 t1 = new ThreadTest01("测试线程1");
ThreadTest01 t2 = new ThreadTest01("测试线程2");
ThreadTest01 t3 = new ThreadTest01("测试线程3");
t1.start();
t2.start();
t3.start();
}
}
}
注意: 1,start()方法调用后不会立刻启动多线程代码,而是使得线变成可运行的状态,什么时候运行取决于操作 系统。线程的执行不是有序的而是乱序的,随机的;
2,start()方法不可以重复调用,人如果重复调用会出现illegalThreadStateExcption
3.程序启动运行main的时候。jvm会启动一个进程,主线程mian在main()调用时被创建,随着satrt() 方法调用,其他线程也启动了。
二,实现java.lang.Runable接口
js
代码如下
public class ThreadTest02 implements Runnable{
private String name;
public ThreadTest02(String name){
this.name=name;
}
@Override
public void run() {
}
注意:
1,ThreadTest02类通过实现Runnable接口的方式使得自己拥有多线程的特征,但实际上Thread类也实 现了Runnable接口
Thread和Runnable的区别
由于Java面向对象的继承性是单继承性,因此使用继承于Thread类的方式实现多线程不利于解决资源共享的问题,而且通过实现Runnable接口的方式实现多线程在处理资源共享等问题方面相对有利。
利用线程同步机制来解决线程安全的问题
方式一,同步代码块
public class ThreadTest01 extends Thread{
private static int ticket=100;
public ThreadTest01(String name) {
super(name);
}
public void run() {
while (true) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (ThreadTest01.class) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
说明:这里使用了关键字synchronized,通过利用同步监视器来确保线程安全,但这样做也有弊端【cpu资源的浪费,效率低下】
方式二,同步方法
public class ThreadTest02 implements Runnable{
private static int ticket=100;
private String name;
public ThreadTest02(String name){
this.name=name;
}
@Override
public synchronized void run() {
while (true) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(ticket>0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
}else{
break;
}
}
}
}
说明:这里则是使用synchronized关键字来修饰run方法来解决线程安全问题
对两种方法的说明
工作机制: 当多个线程中的一个线程进入run方法体中视时,其他的线程只能在同步监视器同步的代码之外等候,直到进入的线程执行完毕,下一个线程才能够进入;
两种方法均有弊端,都浪费了cpu资源
拓展方法:使用ReentrantLock类的对象调用lock(),unlock()方法
public class ThreadTest03 implements Runnable{
private int ticket=100;
ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void run() {
while (ticket!=0) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
reentrantLock.lock();
if(ticket>0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
}else{
break;
}
reentrantLock.unlock();
}
}
}