Java当中的线程(一)

来源:互联网 发布:软件开发业务流程 编辑:程序博客网 时间:2024/06/11 20:14

多进程和多线程

多进程:操作系统(比如android系统)中能(同时)运行多个任务(程序)
多线程:在同一个应用程序中有多个顺序流(同时)执行

线程是进程中的一个流程。
进程像高速公路,线程像高速公路上的车。

原则上,一个软件一个进程。

多线程执行,其实是cpu在多个线程之间互相切换,速度很快,然后看着就像是同时进行。

创建线程类的2种方法

方式1:

定义一个线程类,继承Thread,并重写方法run(),方法run()成为线程体;(由于Java只支持单继承,用这种方法定义的类不能再继承其他类)

class FirstThread extends Thread{public void run(){for(int i = 0; i < 100; i++){System.out.println("FirstThread-->"+i);}}}

class Test{public static void main(String args[]){//生成线程类的对象FirstThread ft = new FirstThread();//启动线程ft.start();}}


上面简单的程序,实际开启了3个线程:1、main线程 2、ft线程 3、回收线程

下面修改程序验证一下main线程的存在
class Test{public static void main(String args[]){//生成线程类的对象FirstThread ft = new FirstThread();//启动线程ft.start();//添加一个循环打印,显示主线程存在for(int i = 0; i < 100; i++){System.out.println("main-->"+i);}}}


从上面可以看出,多线程中,main线程和ft线程,两个线程是互相交替执行的(cpu在两个线程之间交替执行),而且是不规律的。

多线程规律:没谱

有些错误,只在某些执行情况出现,有些时候不出现。

为何不调用run()而是用start()?

如果把上面程序中ft.start()修改成ft.run(),就不是多线程了,而是先执行FirstThread在执行main,结果大家可以自行验证一下。
用start方法,线程是进入就绪状态。进行抢线程的状态。






看不懂图,我也不解释了,看视屏,视频说得更好。

方式二:

实际此方法用得比较多(不用上面方法,原因较多)

提供一个实现接口Runnable的类作为线程的目标对象,在初始化一个Thread类或者Thread子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体。

class RunnableImpl implements Runnable{public void run(){for(int i = 1; i < 100; i++){System.out.println("Runnable-->" + i);}}}

class Test{public static void main(String args[]){//生成一个Runnable接口实现类的对象RunnableImpl ri = new RunnableImpl();//生成一个Thread对象,并将Runnable接口实现类的对象作为参数传递给该Thread对象Thread t = new Thread(ri);//通知Thread对象,执行start方法t.start();}}

看到上面有木有很熟悉的样子?是的,上面其实可以用装饰者模式+匿名内部类,重新写,更方便。
一般我们都不会写RunnableImpl这个类继承Runnable,而是直接用匿名内部类,如下:(当然有些要继承Runnable还是要写的)

Thread t = new Thread(new Runnable(){public void run(){for(int i = 1; i < 100; i++){System.out.println("new Runnable-->" + i);}}});t.start();

或者

new Thread(new Runnable(){public void run(){for(int i = 1; i < 100; i++){System.out.println("new Runnable-->" + i);}}}).start();

上面方式在android开发中常见到这样的线程。呵呵


线程的简单控制方法

中断线程

Thread.sleep() ----休眠完成后进入“就绪”状态,抢占CPU,抢到了就运行。
遇到Thread.sleep(),程序进入“阻塞”状态,结束后,进入“就绪”状态。
注意:比如Thread.sleep(2000); ,该线程真正休眠时间,并不一样是2000毫秒,因为他2000毫秒走完后,并不一样马上抢到CPU
真正休眠时间应该是:2000毫秒+等待抢占cpu的时间。

所以认为,线程休眠2000毫秒,就是停了2000毫秒,这种思想是不对的。

Thread.yield()----遇到这行代码,让出CPU。比如A和B线程,A中遇到Thread.yield()让出CPU,然后A和B都重新进入就绪状态,抢CPU。(谁抢得到那是未知数)

class Test{public static void main(String args[]){Thread t1 = new Thread(new Runnable(){public void run(){for(int i = 1; i < 100; i++){System.out.println("t1-->" + i);if(i == 50){try{Thread.sleep(2000);}catch(Exception e){System.out.println(e);}}}}});t1.start();}}

Thread.sleep();需要try...catch

设置线程优先级

getPriority()
setPriority()

class Test{public static void main(String args[]){Thread t1 = new Thread(new Runnable(){public void run(){for(int i = 1; i < 100; i++){System.out.println("t1-->" + i);}}});// 线程的优先级最大是10,最小是1,默认是5(优先级越大,执行概率越大)// 可以使用Thread所提供的静态常量来设置线程的优先级t1.setPriority(Thread.MAX_PRIORITY);//设置最大优先级// t1.setPriority(Thread.MIN_PRIORITY);//设置最小优先级// t1.setPriority(2);//亲自测试貌似也可以设置常数System.out.println(t1.getPriority());//打印线程优先级t1.start();Thread t2 = new Thread(new Runnable(){public void run(){for(int i = 1; i < 100; i++){System.out.println("t2-->" + i);}}});t2.start();}}

用上面程序可以得到的结果,大概就是t1比t2运行靠前,更多一点。抢到CPU的概率概率大了。反正最好亲手写写程序和看看视频,收获会很多。


线程的同步

多线程数据安全

同步线程的方法

线程同步错误,多个线程公用一份数据的时候,就会出错误,共同抢100张火车票问题。

class MyThread implements Runnable{int i = 100;public void run(){while(true){//Thread.currentThread()获取当前线程 getName()当前线程的名字System.out.println(Thread.currentThread().getName() + i);i--;//让出cpu,让所有线程重新竞争cpu使用权(在这,为了更容易出现想要的错误而写的)Thread.yield();if(i < 0){break;}}}}

class Test{public static void main(String args []){MyThread mt = new MyThread();//生成2个Thread对象,但是两个Thread对象公用同一个线程体对象//等于t1和t2同时在用MyThread(就和大家一起抢火车票一样)Thread t1 = new Thread(mt);Thread t2 = new Thread(mt);t1.setName("t1线程");t2.setName("t2线程");t1.start();t2.start();}}
运行结果就呵呵哒了,t1和t2同时用了100.这个就是同步线程安全问题。



如何解决同步线程安全问题?

synchronized(this){...} 

利用同步锁,谁用了就先占用,别人不能用。
线程锁作用:当一个线程在执行某一段代码块的时候,其他线程不能执行该段代码块。
这样就保证了我们数据的安全。

先将上面两个线程,可能会同时执行的代码块,用synchronized包裹起来,当一个线程执行代码块里面的代码的时候,其他线程必须等该线程执行完成才可以执行(就算抢到了cpu,也得让出来)

class MyThread implements Runnable{int i = 100;public void run(){while(true){synchronized(this){//Thread.currentThread()获取当前线程 getName()当前线程的名字System.out.println(Thread.currentThread().getName() + i);i--;//让出cpu,让所有线程重新竞争cpu使用权(在这,为了更容易出现想要的错误而写的)Thread.yield();if(i < 1){break;}}}}}

但是上面运行后,末尾会出现一个0


如何解决?

深入synchronized关键字

很多人认为这个锁,是锁住了代码,是大错特错的。








0 0