Thread(线程),run(),start()
来源:互联网 发布:java excel预览 编辑:程序博客网 时间:2024/06/11 03:08
进程:一个程序开启的时候,会启动一个进程,在进程中会开启线程,如果只有一个线程,那么这个线程就称为主线程。如果进程停止了,那么会干掉线程再推出。在windows系统上,如果启动一个应用之后推出,但是你在管理器上还能看见这个应用的.exe还在,原因就是里面还有线程在执行任务,把这个应用的.exe干掉,那么就会先干掉里面的线程,再推出。java程序中,我们执行程序的时候,会开启java 的JVM,即启动java JVM的时候会有一个进程:java.exe。在这个进程中至少启动一个线程去执行main函数。线程:就是程序内部的一条执行线索,在程序中,线程的任务就是去执行任务,比如下载获取数据等
线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新
Thread
对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的
main
方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:
- 调用了
Runtime
类的exit
方法,并且安全管理器允许退出操作发生。 - 非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到
run
方法之外的异常。
线程创建的两种方式:
package com.enterise.test.thread;public class CreateThread {public static void main(String[] args) {ThreadOne threadOne = new ThreadOne();threadOne.start();new Thread(new RunnableOne()).start();}}/** * 线程创建方式一: * 继承Thread * @author Always * */class ThreadOne extends Thread {@Overridepublic void run() {super.run();while (true) {try {this.sleep(500);System.out.println("thread :" + this.getName());} catch (InterruptedException e) {e.printStackTrace();}}}}/** * Thread创建方式二: * 实现Runnable * @author Always * */class RunnableOne implements Runnable {@Overridepublic void run() {while (true) {try {new Thread().sleep(500);System.out.println("thread :"+ Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}}}}
继承Thread的线程:当启动这个线程的时候,会调用这个线程的run方法,其实不然,当我们这个run方法是覆盖父类的run方法的时候:
/** * If this thread was constructed using a separate * <code>Runnable</code> run object, then that * <code>Runnable</code> object's <code>run</code> method is called; * otherwise, this method does nothing and returns. * <p> * Subclasses of <code>Thread</code> should override this method. * * @see #start() * @see #stop() * @see #Thread(ThreadGroup, Runnable, String) */ public void run() {if (target != null) { target.run();} }----------------------------/* What will be run. */ private Runnable target;
----------------------------
也就是说当继承thread的run方法覆盖父类,那么会执行父类的run方法,在父类中是去判断target是否为空,这个target是runnable接口,如果这个target不为空,那么就会去执行runnable中的run方法,而不是去执行thread本身的run方法。实验:
package com.enterise.test.thread;public class TestThread {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {while(true){try {new Thread().sleep(500);System.out.println("--runnable->"+Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}}}}){@Overridepublic void run(){//super.run();while(true){try {new Thread().sleep(500);System.out.println("--thread.run->"+Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}}}}.start();}}结果:执行runnable中的run代码。如果有<pre class="java" name="code">super.run();执行thread中的run代码。
实现方式和继承方式的区别:
实现方式和继承方式的区别:实现:避免了单继承的局限性。继承:thread中的run。实现:runnable中的run。
线程的两个方法(run start):start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
package com.enterise.test.thread;public class ThreadTwo {public static void main(String[] args) {MethodThread thread = new MethodThread();thread.start();//thread.run();System.out.println("------main-thread-------");}}class MethodThread extends Thread {private int count = 5;private boolean tag = true;public void run() {while(tag){try {Thread.sleep(500);if(count > 0){count --;System.out.println("--->"+Thread.currentThread().getName());}else {tag = false;}} catch (InterruptedException e) {e.printStackTrace();}}}}
执行结果:start:------main-thread---------->Thread-0--->Thread-0--->Thread-0--->Thread-0--->Thread-0run:--->main--->main--->main--->main--->main------main-thread-------即:调用start方法是启动线程调用run方法。调用run方法是创建了线程,执行run方法,没有开启线程,也就是执行一个类调用里面的方法而已。
线程的几个状态:start();启动线程执行run方法。sleep();线程执行时,遇到sleep,者该线程执行睡眠,当睡眠时间达到的时候,会自动在执行下去。wait();等待,使该线程等待着,进入线程池中。notify();唤醒线程。(线程池:先进先出,唤醒先进去的线程)唤醒一个线程。notifyAll();唤醒所有线程(线程池中的所有线程)stop();停止线程。run();方法执行结束。消亡。运行状态:持有cpu的执行权。临时状态(阻塞):没有cpu执行权(等待cpu的执行权)。冻结状态:放弃了执行资格。(wait、sleep)
线程安全问题:就是多线程在操作同一块代码时对共享数据进行操作,导致数据不合理的情况出现。线程安全问题都是由全局变量及静态变量引起的。即线程操作的是每个线程共享的数据。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。即:引发线程出现安全的前提:1.两个或者两个以上的线程。2.操作的数据是几个线程所共享的。run方法中:if(count > 0){count --;System.out.println("--->"+Thread.currentThread().getName());}else {tag = false;}count:是全局变量。当第一个线程进入判断的代码时,比如是count=1,在没有进行操作--之前,cpu的执行权转到了另外一个线程上,这个时候count还是1,进入判断操作--,此时count=0,然后打印,之后另外一个线程抢到cpu的执行权,执行--操作,打印的数据就成为了-1。这样导致数据的不合理性。问题的根据就是在操作数据的时候几个线程同步进行着,解决问题的办法就是在操作数据的时候只让一条线程执行,等执行完之后,另外一条线程再去执行数据的操作,这样就避免了数据操作的错乱。
package com.enterise.test.thread;public class ThreadTwo {public static void main(String[] args) {Ticket ticket = new Ticket();//开启两条线程执行卖票new Thread(new SellTicketThread(ticket)).start();new Thread(new SellTicketThread(ticket)).start();}}class SellTicketThread implements Runnable {private Ticket ticket;public SellTicketThread(Ticket ticket){this.ticket = ticket;}@Overridepublic void run() {while(ticket.isok){try {Thread.sleep(50);//卖票ticket.sellTicket();} catch (InterruptedException e) {e.printStackTrace();}}}}class Ticket {private int ticketNum = 100;public boolean isok = true;public void sellTicket(){if(ticketNum > 0){ticketNum--;System.out.println("ticiketNum-->"+ticketNum);}else {isok = false;}}}/** * 执行结果: * ticiketNum-->10 ticiketNum-->9 ticiketNum-->9 ticiketNum-->8 ticiketNum-->7 * 出现了两个9 9 * */
同步代码块和同步函数:synchronized
在出现操作共享数据的代码块上加同步代码块:
synchronized (this) {if(ticketNum > 1){ticketNum--;System.out.println("ticiketNum-->"+ticketNum);}else {isok = false;}}
1线程进入同步代码块之前会判断这个锁是否是开的,如果是开的者进去,之后把锁关掉,然后执行数据,其他的线程抢到了cpu的执行权,到锁之前判断锁如果锁是关的者是进不去就在此等候,里面的线程操作数据完毕之后,会把锁打开,其他的线程按照之前的步骤同样执行。
this代表的是锁,只要是任意的对象就可以,如果锁不一致,那么数据还是错乱的原因就是每个线程有各自的锁。
同步函数:public synchronized void sellTicket(){if(ticketNum > 1){ticketNum--;System.out.println("ticiketNum-->"+ticketNum);}else {isok = false;}}
当同步函数是静态的时候:class Ticket {private static int ticketNum = 100;public static boolean isok = true;public static synchronized void sellTicket(){if(ticketNum > 1){ticketNum--;System.out.println("ticiketNum-->"+ticketNum);}else {isok = false;}}}
结果其实还是错乱的:原因是synchronized的锁是this,但是静态函数在jvm加载代码的时候就为这个函数开辟了空间,这个时候还没有这个对象也就是没有this这个概念。
所以static的同步函数的锁是类.class
class Ticket {private static int ticketNum = 100;public static boolean isok = true;public static void sellTicket(){synchronized(Ticket.class){if(ticketNum > 1){ticketNum--;System.out.println("ticiketNum-->"+ticketNum);}else {isok = false;}}}}
daixu----
0 0
- Thread(线程),run(),start()
- 线程 Thread Runnable start run
- 线程Thread类的start()和run()
- java Thread线程run()和start()方法的区别
- Thread线程中start()和run()方法的区别
- Java线程——Thread与Runnable、start()与run()
- Thread的start()和run()
- Thread的start和run
- Thread的run和start
- Thread的start与run
- Thread调用start、run区别
- thread.start和 thread.run 的区别
- Thread.start()和Thread.run()的区别
- java中Thread线程中的 start()和run()方法的区别
- java之Thread线程相关yield()、sleep()、wait()、join()、run和start区别详解
- 线程与进程,Thread的run()与start()的区别
- java多线程-概述-创建线程_继承Thread类-run和start特点
- Java之Thread线程相关yield()、sleep()、wait()、join()、run和start区别详解
- jquery与document转换
- Grunt Gruntfile.js uglify concat watch 基本配置
- 一个适合小公司用的开源数据管道工具
- Chrome 的 开发者工具(F12、devtools)开启缓慢解决方法
- Oracle VM VirtualBox 安装ubuntu系统后如何设置文件夹共享
- Thread(线程),run(),start()
- 剑指offer-面试题25:二叉树中和为某一值的路径
- 谈Runtime机制和使用的整体化梳理
- Objective-C实现一个基于数组下标[index]和字典[@"key"]的访问模式
- Ubuntu14.04 安装Eclipse
- 【CSS3】文字与字体--慕课网【学习总结】
- phpStudy设置301重定向
- PHP Apache Mysql的配置搭建及多站点配置
- Android SurfaceView 学习笔记(二)