Java多线程
来源:互联网 发布:php authorization 编辑:程序博客网 时间:2024/06/05 02:43
1. 实例变量与线程安全
自定义线程类中的实例变量针对其他线程有共享与不共享之分,这在多个线程之间交互时是一个很重要的技术点。
不共享数据的情况:每个线程都有各自的实例变量,多个线程交互时不影响各自的实例变量值,不存在线程安全问题。
共享数据的情况:多个线程访问同一个实例变量,多个线程交互时存在“非线程安全问题”。
“非线程安全”是指多个线程对同一个对象中的实例变量进行操作时值被更改、值不同步的情况,进而影响程序的执行流程。
解决“非线程安全”可以使用synchronized关键字。
2. i–或i++与System.out.println()的异常
看下面例子中,i++与println()联合使用时有可能出现的异常情况:
public class MyThread implements Runnable{ private Integer count = 0; @Override public void run() { System.out.println(Thread.currentThread().getName() + " count = " + (count++)); } public static void main(String[] args) { MyThread myThread = new MyThread(); Thread thread1 = new Thread(myThread); Thread thread2 = new Thread(myThread); Thread thread3 = new Thread(myThread); Thread thread4 = new Thread(myThread); thread1.start(); thread2.start(); thread3.start(); thread4.start(); }}
打印结果:
Thread-0 count = 0Thread-2 count = 3Thread-3 count = 2Thread-1 count = 1
而如果改变run()方法成这样:
@Overridepublic void run() { count++; System.out.println(Thread.currentThread().getName() + " count = " + count);}
则打印结果:
Thread-0 count = 1Thread-3 count = 3Thread-2 count = 2Thread-1 count = 4
由上面实验可知:虽然println方法内部是同步的,但是i++操作是在进入println方法之前发生的,所以有发生非线程安全的概率。
public void println(String x) { synchronized (this) { print(x); newLine(); }}
而i++操作是非原子的,在某些JVM中,i++要分为三步:
a. 取得原有i的值;
b. 计算i + 1;
c. 对i进行赋值;
这三步中,如果有多个线程访问,那么一定会出现非线程安全问题。
为了线程安全,还是需要使用同步方法。
3. currentThread()方法
currentThread()方法可以返回代码段正在被哪个线程调用的信息。
public class MyThread5 extends Thread{ public MyThread5() { System.out.println("construction begin"); System.out.println("Thread.currentThread().getName():" + Thread.currentThread().getName()); System.out.println("this.getName():" + this.getName()); System.out.println("contruction end"); } @Override public void run() { System.out.println("run begin"); System.out.println("Thread.currentThread().getName():" + Thread.currentThread().getName()); System.out.println("this.getName():" + this.getName()); System.out.println("run end"); } public static void main(String[] args) { MyThread5 myThread5 = new MyThread5(); Thread thread = new Thread(myThread5); thread.setName("A"); thread.start(); }}
输出结果:
construction beginThread.currentThread().getName():mainthis.getName():Thread-0contruction endrun beginThread.currentThread().getName():Athis.getName():Thread-0run end
这里的this指该线程类的实例,改线程类继承Thread类,没有对Name重命名,所以在run()方法中通过this.getName()输出的是默认名称:Thread-0。
注意:如果将main方法中创建线程并启动的过程改成下面这种,那么run()方法中的this就代表当前线程:
public static void main(String[] args) { MyThread5 myThread5 = new MyThread5(); /*Thread thread = new Thread(myThread5); thread.setName("A"); thread.start();*/ myThread5.setName("A"); myThread5.start();}
输出结果:
construction beginThread.currentThread().getName():mainthis.getName():Thread-0contruction endrun beginThread.currentThread().getName():Athis.getName():A // 区别run end
4. isAlive()
isAlive()用于判断当前线程是否处于活动状态。活动状态是指线程已经启动且尚未终止。线程处于运行或者就绪状态,就认为线程是“存活”的。
看下面例子通过isAlive()方法区分this和Thread.currentThread()。
public class MyThread extends Thread{ public MyThread() { System.out.println("构造方法 begin"); System.out.println("Thread.currentThread().getName():" + Thread.currentThread().getName()); System.out.println("Thread.currentThread().isAlive():" + Thread.currentThread().isAlive()); System.out.println("this.getName():" + this.getName()); System.out.println("this.isAlive():" + this.isAlive()); System.out.println("构造方法 end"); } @Override public void run() { System.out.println("run begin"); System.out.println("Thread.currentThread().getName():" + Thread.currentThread().getName()); System.out.println("Thread.currentThread().isAlive():" + Thread.currentThread().isAlive()); System.out.println("this.getName():" + this.getName()); System.out.println("this.isAlive():" + this.isAlive()); System.out.println("run end"); } public static void main(String[] args) { MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.setName("A"); thread.start(); }}
输出结果:
构造方法 beginThread.currentThread().getName():mainThread.currentThread().isAlive():truethis.getName():Thread-0this.isAlive():false构造方法 endrun beginThread.currentThread().getName():AThread.currentThread().isAlive():truethis.getName():Thread-0this.isAlive():falserun end
如果main方法改成如下:
public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.setName("A"); myThread.start();}
输出结果:
构造方法 beginThread.currentThread().getName():mainThread.currentThread().isAlive():truethis.getName():Thread-0this.isAlive():false构造方法 endrun beginThread.currentThread().getName():AThread.currentThread().isAlive():truethis.getName():A // 区别this.isAlive():true // 区别run end
将线程对象以构造参数的方式传递给Thread对象进行start()启动线程,我们直接启动的线程是thread,而作为构造参数的myThread,赋值给Thread对象的target,之后通过thread的run方法调用target.run()。此时Thread.currentThread是Thread的引用thread,而this则表示myThread。
5. sleep()
sleep()的作用是在指定毫秒时间内,让当前正在执行的线程休眠(暂停执行)。这个正在执行的线程是指this.currentThread()返回的线程(Thread.currentThread())。
6. getId()
getId()方法的作用的取的线程的唯一标识。比如thread-0的0。
7. yield()
yield()方法的作用是放弃当前的CPU资源,将它让给其他任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。
上述内容总结自《Java多线程编程核心技术》一书。
- 【Java多线程】多线程死锁
- Java 多线程
- java 多线程
- java多线程
- JAVA多线程
- java多线程
- JAVA多线程
- java多线程
- JAVA 多线程
- Java多线程
- java多线程
- JAVA 多线程
- Java 多线程
- Java 多线程
- java多线程
- Java 多线程
- Java多线程
- java 多线程
- 存储器
- 查询网站的IP地址位置
- selenium攻占煎蛋妹子图
- Hbase_命令
- 低层视觉:使用一幅图像——边缘检测
- Java多线程
- 什么星座更适合做程序猿?
- LNMP架构(二)
- Hdu 5833 Zhu and 772002 异或方程组高斯消元
- Zookeeper异常Exception in thread "main" org.apache.zookeeper.KeeperExcep
- myeclipse选中的变量,相关引用的地方高亮
- Python 练习实例16
- OVN架构原理
- 输入一个正整数n,获得该整数低字节中的前4位,并按示例格式输出。