您的位置 首页 php

多线程模式1:java多线程必须掌握的知识

现在很多程序员,搞 java 的就是Spring,做PHP的就是Laravel、TP、YII,然后再掌握些Mysql的基础知识,写几笔sql语言,懂几个业务模型,就称为“大拿”了。其实,干这些工作很少考虑 多线程 ,思维都单向线性的,程序员干个3-5年,水平跟干5-10年其实相差是不大的,无非是唯手熟尔。

小编觉得作为一名以源代码为事业的码农,应该持续不断地学习,不断提高自己的技术水平。今天特开启“java多线程模式”系列,彻底把多线程拦路虎干趴下。

进程、线程、协程的概念,我就不讲了。简单说进程 > 线程 > 协程;进程之间不能共享内存,但线程之间是可共享内存的。废话不多说,先来写一个多线程程序:

⑴ Thread

class MyThread extends Thread {

private int ticket=10;

public void run(){

for ( int i=0;i<20;i++){

if ( this .ticket > 0){

System. out .println(“卖票:ticket”+ this .ticket–);

}

}

}

public static void main(String[] args) {

MyThread mt1 = new MyThread();

mt1. start ();

MyThread mt2 = new MyThread();

mt2.start();

MyThread mt3 = new MyThread();

mt3.start();

}

}

⑵ Runnable

public class MyThread implements Runnable{

private int ticket=10;

public void run(){

for ( int i=0;i<20;i++){

if ( this .ticket > 0){

System. out .println(“卖票:ticket”+ this .ticket–);

}

}

}

public static void main(String[] args) {

MyThread mt = new MyThread();

new Thread(mt).start();// 同一个mt,但是在Thread中就不可以,如果用同一

new Thread(mt).start();// 个实例化对象mt,就会出现异常

new Thread(mt).start();

}

}

编译执行后,你看到了什么不同吗?

同样是启动3个线程去卖票,总共10张票,但extends Thread时售出30张,implements Runnable时售出10张。下面总结下Thread和Runnable的几个知识点:

① 其实Thread也是Runnable的子类。

② Runnable可实现资源共享。

③ 写多线程时,多用implements Runnable,很少用extends Thread。

2、wait(), notify(),notifyAll(),sleep()都有什么不同

⑴ 举个wait,notify的例子:

public class requestQueue{

private final LinkedList queue = new LinkedList();

public synchronized String getRequest(){

while (0 >= queue.size()){

try{

wait();

}catch(InterruptedException e){}

return (String)queue.removeFirst();

}

}

Public synchronized putRequest(String request){

queue.addLast(request);

notifyAll();

}

}

首先有3点必须明确:

①wait(), notify(), notifyAll()是属于Object的方法。Object是java最底层的类,也就是说每个对象都有wait, notify功能。

②我们只能在被synchronized的同步方法或者同步块里面调用wait()和notify()。

③当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同),进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒(由于notify()只是唤醒一个线程,但我们由不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程),线程被唤醒后会进入锁池,等待获取锁标记。

⑵ 举2个sleep的例子

import java.text.SimpleDateFormat;

import java.util.Date;

public class SleepTest {

public static void main(String[] args) throws InterruptedException{

int count = 5;

while(count >= 0){

Thread.sleep(1000);

System.out.println(“current time is:”+new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date()));

count –;

}

}

}

看下,输出什么?你猜是不是该每隔1秒打印出6条时间信息。

图1 输出结果

public class SleepTest extends Thread {

public void run() {

int count = 5;

while(count >= 0){

try {

Thread.sleep(1000);

System.out.println(“current time is:”+new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date()));

} catch (InterruptedException e) {

e.printStackTrace();

}

count –;

}

}

public static void main(String[] args) {

new SleepTest().start();

}

}

这下,又该输出什么?

sleep()方法是属于Thread类的,sleep()方法让程序暂停执行指定的时间,让出cpu,但线程不会释放对象锁。

3、多线程的状态转换

图2 多线程状态图

① 初始状态(new):new了对象后,线程就进入“初始状态”。

② 可运行状态(runnable):当对象调用了start()方法后,该线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。

③ 运行状态(running):线程获得了cpu时间片(timeslice),执行程序代码。

④ 阻塞状态(block):指线程因为某种原因放弃了cpu 使用权,即让出cpu timeslice,暂时停止运行。阻塞的情况分三种:

⑴等待阻塞:运行(running)的线程执行wait()方法, JVM 会把该线程放入等待队列(waitting queue)中。

⑵同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。

⑶其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

⑤ 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

4、Join的说明

举2个例子:

1)

public class JoinTest {

public static void main(String args[]){

Thread t1 = new Thread(){

public void run(){

System. out .println(“aaa”);

}

};

t1.start();

System. out .println(“AAA”);

}

}

输出什么?

2)

public class JoinTest {

public static void main(String args[]) throws InterruptedException{

Thread t1 = new Thread(){

public void run(){

System. out .println(“aaa”);

}

};

t1.start();

t1.join();

System. out .println(“AAA”);

}

}

又输出什么?

thread.join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的join()方法,直到线程A执行完毕后,才会继续执行线程B。join其实就是使异步执行线程转为同步执行。

5、yeild()的说明

放弃对当前CPU的占用,进入可运行状态。不过这类方法,没事最好不要去用。其实多线程就简单几个方法用用就好。

6、stop(), suspend(),resume()都已经被弃用。

文章来源:智云一二三科技

文章标题:多线程模式1:java多线程必须掌握的知识

文章地址:https://www.zhihuclub.com/149203.shtml

关于作者: 智云科技

热门文章

网站地图