别样JAVA学习(七)多线程上

1、多线程-用途

       CPU是以时间片的方式为进程分配CUP处理时间的,当一个进程以同步的方式去完成几件事情时,此进程必须完成了第一件事情以后再做第二件事,如此按顺序地向CPU请求完成要做的事情。在此单线程的工作模式下,如果把CUP看作是一共有100个时间片的话,CPU可能一直都只是花了其中的10个时间片来处理当前进程所要做的事情,只是用到了CPU的10%的时间片,而其他时间都白白浪费了,当然,实际上CPU的工作模式还是做完一件事以后再去做另一件事,只是CUP的处理速度非常快,很快就处理完成所请求的情事。

       为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而互不干扰,如当前进程要完成三件事情1、2、3,那么CPU会分别用10%的时间来同时处理这3件事情,从而让CPU的使用率达到了30%,大大地提高了CPU的利用率。多线程的好处在处理一些特殊的场合其优势尤其明显。比如下载文件,你要一边下载一边显示进度一边保存,在这种情况下,如果没有用多线程的话,没有意外的话一般都会把主线程阻塞,比如进度条的进度根本没有随着已下载的量而变化,堪至是整个窗体都动不了,用多线程就可以很好地解决这个问题。
   
   这里有一个生活实例可能更好地去理解多线程:回去看你女朋友做饭,正常的话她都会把洗好的菜(肉)先放到锅里煮,然后一边洗别的菜或处理别的事情,如:洗碗、收拾桌台准备开饭,人还是一个人,但她同时做几件事情,这样就可以大大地提高效率。总的一句话就是:CPU还是要花同样多的时间去完成所有的事情,但多线程可以让CPU掺插地同时做多件事情,在视觉上让用户觉得计算机在同时帮他处理多件事情,更好地改善用户体验。

       了解了多线程的好处以后,就要了解应该在什么样的情况下使用多线程技术。因为并不是说所有情况下用多线程都是好事,因为多线程的情况下,CPU还要花时间去维护,CPU处理各线程的请求时在线程间的切换也要花时间,所以一般情况下是可以不用多线程的,用了有时反而会得不偿失。大多情况下,要用到多线程的主要是需要处理大量的IO操作时或处理的情况需要花大量的时间等等,比如:读写文件、视频图像的采集、处理、显示、保存等。

 

多线程的运用比如:聊天室

多线程的运用和好处 - 粉红色的夏天 - 幸福小公主

 
数据库表的复制的停止,需要一个线程在完成一个工作,比如进行复制工作。一个线程可以完成另一个工作,比如停止复制,将flag设为false等。如果只有一个线程,那么就智能完成一件事,要么复制,要么停止,不利于灵活性和实际情况。

www服务器等也是要多线程,来让不同的用户可以进行连接访问。


2、多线程-概述

进程:是一个正在执行中的程序。

              每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。

线程:就是进程中的一个独立的控制单元。

              线程在控制着进程的执行。

一个进程中至少有一个线程。


Java VM    启动的时候会有一个进程java.exe。


该进程中至少一个线程负责java程序的执行。

而且这个线程运行的代码存在于main方法中。

该线程称之为主线程。


扩展:其实更细节说jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。


3、创建线程-继承Thread类

如何在自定义的代码中,自定义一个线程呢?

通过对api的查找,java已经提供了对线程这类事物的描述,就Thread类。


创建线程的第一种方式:继承Thread类。

步骤:

1,定义类继承Thread。

2,复写Thread类中的run方法。

         目的:将自定义代码存储在run方法,让线程运行。

3,调用线程的start方法,

         该方法两个作用:启动线程,调用run方法。


多个线程在抢占CPU资源,例如早期病毒(就是一直抢占电脑CPU资源,电脑死机了)

双核以后,内存就是瓶颈。


发现运行结果每一次都不同。

因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行。

明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)

cpu在做着快速的切换,以达到看上去是同时运行的效果。

我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。


这就是多线程的一个特性:随机性。

谁抢到谁执行,至于执行多长,cpu说的算。


4、创建线程-run和start特点

为什么要覆盖run方法呢?


Thread类用于描述线程。

该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。


也就是说Thread类中的run方法,用于存储线程要运行的代码。


5、获取线程对象以及名称

class Test extends Thread
{
	private String name;
	Test(String name)
	{
		this.name=name;
	}
	public void run()
	{
		for(int x=0;x<60;x++)
		{
			System.out.println(this.getName()+"test..."+x);//获取线程名称
		}
	}
}
class ThreadTest
{
	public static void main(String[] args)
	{
		Test t1=new Test("one");
		Test t2=new Test("two");
		t1.start();
		t2.start();
		for(int x=0;x<60;x++)
		{
			System.out.println("main....."+x);
		}
	}
}

由运行结果可看出线程都有自己默认的名称。

Thread-编号    该编号从0开始

class Test extends Thread
{
	//private String name;
	Test(String name)
	{
		//this.name=name;
		super(name);
	}
	public void run()
	{
		for(int x=0;x<60;x++)
		{
			System.out.println(Thread.currentThread().getName()+"test..."+x);//获取线程名称
		}
	}
}

Thread.currentThread():获取当前线程对象。

getName():获取线程名称。

设置线程名称:setName或者构造函数。


6、售票的例子

class Ticket extends Thread
{
	static private int tick=100;
	public void run()
	{
		while(true)
		{
			if(tick>0)
			{
				System.out.println(currentThread().getName()+"sale:"+tick--);
			}
		}
	}
}
class TicketDemo
{
	public static void main(String[]args)
	{
		Ticket t1=new Ticket();
		//Ticket t2=new Ticket();
		//Ticket t3=new Ticket();
		//Ticket t4=new Ticket();
		t1.start();
		t1.start();
		t1.start();
		t1.start();
	}
}
结果:



7、创建线程-实现Runnable接口

Runnable为非Thread子类的类提供了一种激活方式。

class Ticket implements Runnable//extends Thread
{
	static private int tick=100;
	public void run()
	{
		while(true)
		{
			if(tick>0)
			{
				System.out.println(Thread.currentThread().getName()+"sale:"+tick--);
			}
		}
	}
}
class TicketDemo
{
	public static void main(String[]args)
	{
		/*
		Ticket t1=new Ticket();
		//Ticket t2=new Ticket();
		//Ticket t3=new Ticket();
		//Ticket t4=new Ticket();
		t1.start();
		t1.start();
		t1.start();
		t1.start();
		*/
		Ticket t=new Ticket();//不是线程;
		Thread t1=new Thread(t);//创建了一个线程;
		Thread t2=new Thread(t);//创建了一个线程;
		Thread t3=new Thread(t);
		Thread t4=new Thread(t);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
结果完好。


创建线程的第二种方式:实现Runnable接口

步骤:

1,定义类实现Runnable接口。

2,覆盖Runnable接口中的run方法。

         目的:将自定义的代码存储在run方法,让线程运行。

3,通过Thread类建立类对象。

4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。

         目的:自定义run方法所属对象是Runnable接口的子类对象,

                    所以要让线程去指定指定对象的run方法。

5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。


实现方式和继承方式区别:

1,实现方式避免了单继承的局限性。在定义线程时,建议使用实现方式。

2,存放的资源被共享,位置不同。





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值