Java多线程基础知识总结(一)
终于有机会总结一下多线程了,java的多线程一直是一个重要的问题(在面试中),所以了解java的多线程的知识对找一个好工作至关重要。
今天正好在准备面试,就简单的总结一下java的多线程的知识。
多线程的实现方法
多线程的实现方法有两种,一种方法是继承Thread,并实现其中的run方法;另一种是实现runnable接口:
//1、继承thread
public class New_thread extends Thread{
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test_thread{
public static void main(String[] args) {
New_thread run=new New_thread();
run.start();
System.out.println("测试完成");
}
}
//2、实现runnable接口
public class New_runnable implements Runnable{
public void run(){
System.out.println("running!");
}
}
public class Test_thread{
public static void main(String[] args) {
New_runnable run=new New_runnable();
Thread test=new Thread(run);
test.start();
System.out.println("测试完成");
}
}
一旦涉及多线程就有可能造成数据的不一致性,会有共享数据的竞争条件。
如下所示代码:
public class New_thread extends Thread{
private int count=5;
public void run() {
count--;
System.out.println(count+" "+Thread.currentThread().getName());
}
}
public class Test_thread{
public static void main(String[] args) {
New_thread test=new New_thread();
Thread t1=new Thread(test);
Thread t2=new Thread(test);
Thread t3=new Thread(test);
Thread t4=new Thread(test);
Thread t5=new Thread(test);
t1.start();t2.start();t3.start();t4.start();t5.start();
}
}
上述代码运行结果为:
synchronized关键字
这个关键字的作用是:让标志以后的代码进行顺序执行,而不是并行执行。这样可以有效的解决刚刚的数据的不一致性的问题。
public class New_thread extends Thread{
private int count=5;
synchronized public void run() {
count--;
System.out.println(count+" "+Thread.currentThread().getName());
}
}
运行以后结果为:
currentThread方法
返回当前运行的线程
public class New_thread extends Thread{
public New_thread() {
System.out.println(Thread.currentThread().getName());
System.out.println(this.getName());
}
synchronized public void run() {
System.out.println(Thread.currentThread().getName());
System.out.println(this.getName());
}
}
public class Test_thread{
public static void main(String[] args) {
New_thread test=new New_thread();
Thread a=new Thread(test);
a.setName("a");
a.start();;
}
}
isAlive()方法
判断当前线程是否处于活跃状态。当前线程是currentThread返回的线程的名称
public class New_thread extends Thread{
public New_thread() {
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().isAlive());
System.out.println(this.getName());
System.out.println(this.isAlive());
}
public void run() {
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().isAlive());
System.out.println(this.getName());
System.out.println(this.isAlive());
}
}
public class Test_thread{
public static void main(String[] args) {
New_thread test=new New_thread();
Thread t=new Thread(test);
System.out.println("1 "+t.isAlive());
t.setName("T");
t.start();
System.out.println("2 "+t.isAlive());
}
}
这次的运行结果表示,当前运行的线程并不一定是我们定义的线程,也有可能是当前调用管理我们的线程的线程,所以程序的输出结果是有差异的。
thread.sleep()方法
让“正在执行的线程”进入休眠,休眠指定毫秒数,“正在执行的线程”是指this.currentThread返回的线程
public class New_thread extends Thread{
public void run() {
try {
System.out.println(this.currentThread().getName()+" "+System.currentTimeMillis());
Thread.sleep(1000);
System.out.println(this.currentThread().getName()+" "+System.currentTimeMillis());
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test_thread{
public static void main(String[] args) {
try {
New_thread test=new New_thread();
System.out.println(System.currentTimeMillis());
test.start();
Thread.sleep(2000);
System.out.println(System.currentTimeMillis());
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
getId()方法
作用是取得线程的唯一的标识。当当前执行代码的线程名称是main的时候,线程id值设置为1。其余的标识大家可以自行尝试。
停止线程
停止线程是一个有意思的事情,因为线程没有像break的方法来进行停止的方法。绝大多数使用interrupt的方法来停止一个线程。但是并不是终止一个正在运行的进程,还需要加入一个判断才可以完成线程的终止。
java有三种终止线程的方法:
1、使用退出标志;
2、使用stop方法强行终止一个线程;
3、使用interrupt方法中断线程。
interrupt方法
interrupt方法没有办法直接的停止线程,只能简单的打下标记
public class New_thread extends Thread{
public void run() {
for(int i=0;i<50000l;i++) {
System.out.println(i+1);
}
}
}
public class Test_thread{
public static void main(String[] args) {
try {
New_thread test=new New_thread();
test.start();
Thread.sleep(2000);
Thread.interrupted();
}catch(InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
}
}
想要真正的停止一个线程需要加一个判断条件,在判断条件中加入真正停止的方法。
判断是否停止的方法
public class Test_thread{
public static void main(String[] args) {
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().interrupted());
System.out.println(Thread.currentThread().interrupted());
}
}
结果:
public class Test_thread{
public static void main(String[] args) {
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread().isInterrupted());
}
}
结果:
this.interrupted():测试当前线程是否已经中断,执行以后将状态标志清除为false的功能
this.isInterrupted():测试线程是否已经中断,但是不清除状态标志
下面介绍能够终止线程的方法:
第一种,异常终止法:
将终止以后的线程打入“冷宫”——错误捕捉部分代码,就永远别想出来啦。
public class New_thread extends Thread{
public void run() {
try {
for(int i=0;i<50;i++) {
System.out.println(i+1);
if(this.interrupted()) {
throw new InterruptedException();
}
}
}catch(InterruptedException e) {
System.out.println("打入冷宫!永远不得外出");
e.printStackTrace();
}
}
}
public class Test_thread{
public static void main(String[] args) {
try {
New_thread test=new New_thread();
test.start();
Thread.sleep(1);
test.interrupt();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
第二种、睡眠终止法:
在睡梦中被终止,可怜的线程。
public class New_thread extends Thread{
public void run() {
try {
System.out.println("开始运行");
Thread.sleep(20000);
System.out.println("运行结束");
}catch(InterruptedException e) {
System.out.println("在睡梦中被杀死,可怜的线程!");
e.printStackTrace();
}
}
}
public class Test_thread{
public static void main(String[] args) {
try {
New_thread test=new New_thread();
test.start();
Thread.sleep(100);
test.interrupt();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
结果:
第三种、暴力终止法
说一句实话,我就是很喜欢这种方法,暴力简单直接。
public class New_thread extends Thread{
public void run() {
try {
for(int i=0;i<50;i++) {
System.out.println(i+1);
this.sleep(1);
}
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test_thread{
@SuppressWarnings("deprecation")
public static void main(String[] args) {
try {
New_thread test=new New_thread();
test.start();
Thread.sleep(10);
test.stop();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
结果:
stop方法可以抛出ThreadDeath的异常,使用起来如下所示:
public class New_thread extends Thread{
public void run() {
try {
this.stop();
}catch(ThreadDeath e) {
System.out.println("一个出生就为了自杀的线程!");
e.printStackTrace();
}
}
}
public class Test_thread{
public static void main(String[] args) {
try {
New_thread test=new New_thread();
test.start();
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
虽然我很喜欢stop但是总是有很多人说stop方法不好,会造成很多的数据的不一致性,好吧,这个确实有问题,但是什么代码没有风险呢?个人觉得只要小心,明白原理,任何代码都可以发挥它应有的作用的。
举个小栗子吧!
public class LoginClass {
private String usr="1";
private String psw="111";
public void setString(String s1,String s2){
try {
this.usr=s1;
if(this.usr.equals("a")) {
Thread.sleep(10000);
}
this.psw=s2;
}catch(InterruptedException e) {
e.printStackTrace();
}
}
public String printString() {
return usr+" "+psw;
}
}
public class New_thread extends Thread{
private LoginClass object;
public New_thread(LoginClass object) {
this.object=object;
}
public void run() {
object.printString("b", "bb");
}
}
public class Test_thread{
public static void main(String[] args) {
try {
LoginClass object=new LoginClass();
New_thread test=new New_thread(object);
test.start();
Thread.sleep(10);
test.stop();
System.out.println(object.getName()+" "+object.getPass());
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
使用return终止线程
public class New_thread extends Thread{
public void run() {
for(int i=0;i<50;i++) {
System.out.println(i+1);
if(this.interrupted()) {
return;
}
}
}
}
public class Test_thread{
public static void main(String[] args) {
try {
New_thread test=new New_thread();
test.start();
test.interrupt();
Thread.sleep(10);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
当然大部分人最建议使用抛出异常的方式,我也是这样(虽然我很喜欢暴力终止的方法),毕竟有了异常就可以将异常向上抛去,将线程终止的事件传播开来。
今天先写到这里,线程的内容太多太多,今天大概只写了一半的内容,另外一半另发一篇文章,方便大家查阅。