Java基础_Thread(一)
2016-06-28 17:59
344 查看
1:继承Thread的方式
继承Thread
实现runnable接口
实现runnable接口更容易达到多继承的特性
线程的状态图
2:在多线程技术中,代码是顺序执行的吗? 不是
程序输出:
运行结束!
MyThread
解释:在我们的Run类里面,其有一个主线程,当调用子线程的start方法的时候,即通知“线程规划器”此线程已经准备就绪,等待调用线程的run方法,这个过程其实就是让系统安排一个时间来调用Thread的run方法,也就是启动线程,使其具有异步执行效果。这里就带出一个线程的特性:线程具有随机特性。
问题一:这里会先打印MyThead,再打印 运行结束!吗? 不会
解释:Run类是主线程,其是向下执行的,子线程MyThread具有随机性,需要系统调用。举个例子
这里就需要等待第一个循环做完,才会打印“上面的循环执行完了”,然后等待第二个线程执行完,才会打印“执行完毕”
问题二:调用线程的start方法就是线程的执行顺序吗? 不是
解释:调用start方法只是让线程进入就绪状态,还需要系统分配时间片给线程让其进入运行状态,因此调用start方法的顺序不是线程的执行顺序
问题三:多次调用线程的start方法是否可以? 不可以
会抛出异常“IllegalThreadStateException”
3:实例变量与线程安全
自定义线程类中的实例变量针对其他线程可以有共享与不共享之分。
例如:
实现非共享的方式:
此时每个线程都有各自的count变量,自己减少自己的count变量的值
实现共享的方式:
此时每一个线程共享一个count。但是这样的方式就产生了“非线程安全”的问题。
非线程安全是指:多个线程对同一个对象的同一个实例变量进行操作时,会出现值被更改,值不同步的问题。
解决“非线程安全”问题的方法之一:添加synchronize关键字
原因:多线程访问一个带有synchronize关键字的方法的时候,以排队的方式进行处理,当一个线程调用synchronize方法时,会尝试去拿这把锁,如果能够拿到,则可以执行,否则这个线程就会不断尝试拿这把锁,直到能够拿到为止。而且是多个线程同时去抢这把锁。
1):synchronize方法
也就是同步方法,它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。
当考虑阻塞时,一定要注意哪个对象正被用于锁定:1、调用同一个对象中非静态同步方法的线程将彼此阻塞。如果是不同对象,则每个线程有自己的对象的锁,线程间彼此互不干预。 2、调用同一个类中的静态同步方法的线程将彼此阻塞,它们都是锁定在相同的Class对象上。 3、静态同步方法和非静态同步方法将永远不会彼此阻塞,因为静态方法锁定在Class对象上,非静态方法锁定在该类的对象上。 4、对于同步代码块,要看清楚什么对象已经用于锁定(synchronized后面括号的内容)。在同一个对象上进行同步的线程将彼此阻塞,在不同对象上锁定的线程将永远不会彼此阻塞。
特例:println方法和i–表达式
println()方法内部是同步的,即其内部实现了synchronize效果。但是上面的方法依旧会代码“非线程安全”问题,因为i–的操作是在进入println()方法前发生,因此有发生非线程安全的问题的概率。
4: 实例化Thread分析,线程的名字,Thread=0的来历
在这个过程中会调用Thread的构造函数
因此就产生了Thread-0,Thread-1…等
5: Thread.currentThread().getName() 和 this.getName()的分析
输出为:
分析如下:Thread.currentThread()表示执行该处代码的线程的引用,而this表示当前类的引用。
因此在run方法中的this.getName()表示执行CountOperate类的getName方法,但是CountOperate没有getName方法,则其是执行Thread的getName方法。
继承Thread
实现runnable接口
实现runnable接口更容易达到多继承的特性
线程的状态图
2:在多线程技术中,代码是顺序执行的吗? 不是
public class MyThread extends Thread { @Override public void run() { super.run(); System.out.println("MyThread"); } }
public class Run { public static void main(String[] args) { MyThread mythread = new MyThread(); mythread.start(); System.out.println("运行结束!"); } }
程序输出:
运行结束!
MyThread
解释:在我们的Run类里面,其有一个主线程,当调用子线程的start方法的时候,即通知“线程规划器”此线程已经准备就绪,等待调用线程的run方法,这个过程其实就是让系统安排一个时间来调用Thread的run方法,也就是启动线程,使其具有异步执行效果。这里就带出一个线程的特性:线程具有随机特性。
问题一:这里会先打印MyThead,再打印 运行结束!吗? 不会
解释:Run类是主线程,其是向下执行的,子线程MyThread具有随机性,需要系统调用。举个例子
public class Run { public static void main(String[] args) { for(int i = 0 ; i < 5000 ; i++){ System.out.println("i=" + i); } System.out.println("上面的循环执行完了"); for(int j = 0 ; j < 5000 ; j++){ System.out.println("j=" + j); } System.out.println("执行完毕"); } }
这里就需要等待第一个循环做完,才会打印“上面的循环执行完了”,然后等待第二个线程执行完,才会打印“执行完毕”
问题二:调用线程的start方法就是线程的执行顺序吗? 不是
解释:调用start方法只是让线程进入就绪状态,还需要系统分配时间片给线程让其进入运行状态,因此调用start方法的顺序不是线程的执行顺序
问题三:多次调用线程的start方法是否可以? 不可以
会抛出异常“IllegalThreadStateException”
3:实例变量与线程安全
自定义线程类中的实例变量针对其他线程可以有共享与不共享之分。
例如:
public class MyThread extends Thread { private int count=5; @Override synchronized public void run() { super.run(); while(count > 0){ count--; System.out.println("由 "+t c3b4 his.currentThread().getName()+" 计算,count="+count); } } }
实现非共享的方式:
MyThread mythreadA = new MyThread("A"); MyThread mythreadB = new MyThread("B"); MyThread mythreadB = new MyThread("C"); mythreadA.start(); mythreadB.start(); mythreadC.start();
此时每个线程都有各自的count变量,自己减少自己的count变量的值
实现共享的方式:
MyThread mythreadA = new MyThread(); Thread a = new Thread(mythreadA,"A"); Thread b = new Thread(mythreadB,"B"); Thread b = new Thread(mythreadC,"C"); a.start(); b.start(); c.start();
此时每一个线程共享一个count。但是这样的方式就产生了“非线程安全”的问题。
非线程安全是指:多个线程对同一个对象的同一个实例变量进行操作时,会出现值被更改,值不同步的问题。
解决“非线程安全”问题的方法之一:添加synchronize关键字
原因:多线程访问一个带有synchronize关键字的方法的时候,以排队的方式进行处理,当一个线程调用synchronize方法时,会尝试去拿这把锁,如果能够拿到,则可以执行,否则这个线程就会不断尝试拿这把锁,直到能够拿到为止。而且是多个线程同时去抢这把锁。
1):synchronize方法
也就是同步方法,它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。
当考虑阻塞时,一定要注意哪个对象正被用于锁定:1、调用同一个对象中非静态同步方法的线程将彼此阻塞。如果是不同对象,则每个线程有自己的对象的锁,线程间彼此互不干预。 2、调用同一个类中的静态同步方法的线程将彼此阻塞,它们都是锁定在相同的Class对象上。 3、静态同步方法和非静态同步方法将永远不会彼此阻塞,因为静态方法锁定在Class对象上,非静态方法锁定在该类的对象上。 4、对于同步代码块,要看清楚什么对象已经用于锁定(synchronized后面括号的内容)。在同一个对象上进行同步的线程将彼此阻塞,在不同对象上锁定的线程将永远不会彼此阻塞。
特例:println方法和i–表达式
public class MyThread extends Thread { private int i = 5; @Override public void run() { System.out.println("i=" + (i--) + " threadName=" + Thread.currentThread().getName()); } }
println()方法内部是同步的,即其内部实现了synchronize效果。但是上面的方法依旧会代码“非线程安全”问题,因为i–的操作是在进入println()方法前发生,因此有发生非线程安全的问题的概率。
4: 实例化Thread分析,线程的名字,Thread=0的来历
public class MyThread extends Thread { @Override public void run() { } } MyThread myT = new MyThread (); Thread t1 = new Thread(myT);
在这个过程中会调用Thread的构造函数
public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; }
因此就产生了Thread-0,Thread-1…等
5: Thread.currentThread().getName() 和 this.getName()的分析
public class CountOperate extends Thread { public CountOperate() { System.out.println("CountOperate---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("CountOperate---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"); } }
输出为:
CountOperate---begin Thread.currentThread().getName()=main Thread.currentThread().isAlive()=true this.getName()=Thread-0 this.isAlive()=false CountOperate---end run---begin Thread.currentThread().getName()=A Thread.currentThread().isAlive()=true this.getName()=Thread-0 this.isAlive()=false run---end
分析如下:Thread.currentThread()表示执行该处代码的线程的引用,而this表示当前类的引用。
因此在run方法中的this.getName()表示执行CountOperate类的getName方法,但是CountOperate没有getName方法,则其是执行Thread的getName方法。
相关文章推荐
- 在Struts2中实现Web系统的初始化工作
- Java三大特性之---封装
- Java开源规则引擎-Drools
- Spring Boot中使用JavaMailSender发送邮件
- java.lang.OutOfMemoryError:GC overhead limit exceeded
- 玩转Eclipse开发工具(六)
- JAVA中null,"",equals,==相互之间使用详解
- Java动态代理
- 搭建rtmp直播流服务之2:使用java实现ffmpeg命令接口化调用(用java执行ffmpeg命令)
- 深入理解Java的接口和抽象类
- Spring Boot新模块devtools
- Java设计模式 -- 观察者模式
- Struts2拦截器权限学习心得
- Eclipse导出doc文档以及编码 GBK 的不可映射字符
- Arrays.asList()和Collections.addAll()的性能比较
- spring spel表达式语言
- spring boot 不同的环境使用不同的配置
- java IO之文件输入输出流
- 构建自己的Java Web框架(三)之JAVA反射机制
- Java内部类和外部类互相访问问题