-------
android培训、
java培训、期待与您交流! ----------
务。
象这样的每个子任务都叫作一个“线程”(Thread)。编写程序时,可将每个线程都想象成独立运行,而且
都有自己的专用 CPU。一些基础机制实际会为我们自动分割 CPU 的时间。我们通常不必关心这些细节问题,
所以多线程的代码编写是相当简便的。
这时理解一些定义对以后的学习狠有帮助。“进程”是指一种“自包容”的运行程序,有自己的地址空间。
“多任务”操作系统能同时运行多个进程(程序)——但实际是由于 CPU 分时机制的作用,使每个进程都能
循环获得自己的 CPU 时间片。但由于轮换速度非常快,使得所有程序好象是在“同时”运行一样。“线程”
是进程内部单一的一个顺序控制流。因此,一个进程可能容纳了多个同时执行的线程。
进程太浪费资源,进程切换需要花时间
程序有一个入口一个出口和一个顺序执行的序列,程序执行过程的任何时刻都只有一个单独的执行点
多线程的优势:
多线程编程简单,高效(能直接共享数据和资源,多进程不能)
适合开发服务程序(web服务,聊天服务等)
为创建一个线程,最简单的方法就是从 Thread 类继承。这个类包含了创建和运行线程所需的一切东西。
Thread 最重要的方法是 run()。但为了使用 run(),必须对其进行过载或者覆盖,使其能充分按自己的吩咐
行事。因此,run()属于那些会与程序中的其他线程“并发”或“同时”执行的代码。
创建一个继承Thread的类A,
并重写从Thread继承来的run方法,
构造一个A类对象aa,
调用aa对象的start方法(start方法从Thread继承来,会创建一个新线程,并自动调用aa对象的run方法).
注意:直接调用run方法不会创建线程
执行一个线程就是执行该线程的run方法
执行完aa.start()表示aa线程具有了可以立即被cpu执行的资格,
但由于抢占cpu执行的线程很多,cpu不一定立即执行aa线程
一个Thread对象只能代表一个线程,不能调用两次start方法
定义一个实现Runnable接口的类A,
创建A类对象aa,
利用aa构造一个Thread对象tt ,(Thread中的一个构造方法public Thread(Runnable r))
Thread tt = new Thread(aa);
调用tt中的start方法.
注意:Runnable接口中只有一个void run()方法
Thread类中的常用方法
public final void setName(Sting name)设置当前线程的名字
public static Thread currentThread()返回对当前正在执行的线程的对象的引用 public final String getName()返回当前线程的名字
线程的三个状态:就绪状态,运行状态,阻塞状态
线程控制的基本方法
isAlive()判断线程是否还未终止(三个状态都是活着)
getPriority()获得线程的优先级
setPriority()设置线程的优先级
Thread.sleep()让当前线程睡眠指定毫秒(由运行到阻塞)
join()调用某线程的该方法,将当前线程与该线程合并,即等待该线程结束,再恢复当前线程的运行
yield()让出cpu,当前线程进入就绪队列等待调度(由运行到就绪)
wait()当前线程进入对象wait pool
notify()/notifyAll() 唤醒对象的wait pool中的一个/所有等待进程
线程的优先级从1到10,主线程的缺省优先级是5,子线程的优先级默认和其父线程相同 java提供一个线程调度器监控程序启动后进入就绪状态的所有线程,按线程优先级决定执行顺序
Thread.MIN_PRIORITY = 1
Thread.NORMAL_PRIORITY = 5
Thread.MAX_PRIORTIY = 10
获得和设置线程对象的优先级
int getPriority();
void setPriority(int newPriority)
通常优先级高的线程先于优先级低的线程执行,但不总是这样,实际开发中并不单纯依赖优先级来决定线程运行次序
暂停执行当前运行的线程,使之进入阻塞状态,经过指定的延迟时间后再醒来并进入到就绪状态
Thread类提供的方法
public static void sleep(long millis)
public static void sleep(long millis, int
会抛出InterruptedException异常,必须用try catch捕获子类继承Thread类或实现Runnable接口的run方法都不能抛出异常
成的:
调用 sleep(毫秒数),使线程进入“睡眠”状态。在规定的时间内,这个线程是不会运行的。
用 suspend()暂停了线程的执行。除非线程收到 resume() 消息,否则不会返回“可运行”状态。
用 wait()暂停了线程的执行。除非线程收到 nofify() 或者 notifyAll()消息,否则不会变成“可运行”
线程正在等候一些 IO(输入输出)操作完成。
线程试图调用另一个对象的“同步”方法,但那个对象处于锁定状态,暂时无法使用。
访问那个对象——所以一个线程完全可能等候另一个对象,而另一个对象又在等候下一个对象,以此类推。
这个“等候”链最可怕的情形就是进入封闭状态——最后那个对象等候的是第一个对象!此时,所有线程都
会陷入无休止的相互等待状态,大家都动弹不得。我们将这种情况称为“死锁”。尽管这种情况并非经常出
现,但一旦碰到,程序的调试将变得异常艰难。
让出cpu,给其他线程执行的机会
运行中的线程主动放弃当前获得cpu处理的机会,进入就绪状态
public static void yield()
在多线程程序中,如果一个线程运行的过程用到了另一个线程的运行结果,则可以进行线程的串行化处理
public final void join() throws InterruptedException
t.join()暂停执行t.join()的这个线程,等待t线程运行完毕,这个线程才会获得继续执行的机会
synchronized关键字
synchronized可以修饰一个方法或方法内的某个代码块
synchronized修饰代码块
格式:
synchronized(随便一个类对象名aa)
{
同步代码块
}
说明:
判断aa是否被其他线程霸占,如果发现已霸占,当前线程等待,如果没有被霸占当前线程霸占aa对象,执行同步代码块,执行完自动释放对aa的霸占,线程再次竞争对aa的霸占,cpu会选择一个线程霸占aa
结果:一个线程操作某资源时,不允许其他线程操作该资源,即一次只允许一个线程处理该资源
synchronized修饰方法时,实际霸占的是该方法的this指针所指向的对象,即正在调用该方法的对象
霸占的专业术语叫锁定,霸占住对象专业术语叫监听器
线程
什么是线程:
专业定义:
利用对象,可将一个程序分割成相互独立的区域。我们通常也需要将一个程序转换成多个独立运行的子任务。
象这样的每个子任务都叫作一个“线程”(Thread)。编写程序时,可将每个线程都想象成独立运行,而且
都有自己的专用 CPU。一些基础机制实际会为我们自动分割 CPU 的时间。我们通常不必关心这些细节问题,
所以多线程的代码编写是相当简便的。
这时理解一些定义对以后的学习狠有帮助。“进程”是指一种“自包容”的运行程序,有自己的地址空间。
“多任务”操作系统能同时运行多个进程(程序)——但实际是由于 CPU 分时机制的作用,使每个进程都能
循环获得自己的 CPU 时间片。但由于轮换速度非常快,使得所有程序好象是在“同时”运行一样。“线程”
是进程内部单一的一个顺序控制流。因此,一个进程可能容纳了多个同时执行的线程。
通俗定义:
线程是一个程序里的不同执行路径
为什么需要线程:
进程太浪费资源,进程切换需要花时间
线程的使用和请注意事项:
单线程:
程序有一个入口一个出口和一个顺序执行的序列,程序执行过程的任何时刻都只有一个单独的执行点
多线程:
在单个程序内部在同一时刻可以进行多种运算多线程的优势:
多线程编程简单,高效(能直接共享数据和资源,多进程不能)
适合开发服务程序(web服务,聊天服务等)
创建线程的方法:
为创建一个线程,最简单的方法就是从 Thread 类继承。这个类包含了创建和运行线程所需的一切东西。
Thread 最重要的方法是 run()。但为了使用 run(),必须对其进行过载或者覆盖,使其能充分按自己的吩咐
行事。因此,run()属于那些会与程序中的其他线程“并发”或“同时”执行的代码。
第一种:
创建一个继承Thread的类A,
并重写从Thread继承来的run方法,
构造一个A类对象aa,
调用aa对象的start方法(start方法从Thread继承来,会创建一个新线程,并自动调用aa对象的run方法).
注意:直接调用run方法不会创建线程
执行一个线程就是执行该线程的run方法
执行完aa.start()表示aa线程具有了可以立即被cpu执行的资格,
但由于抢占cpu执行的线程很多,cpu不一定立即执行aa线程
一个Thread对象只能代表一个线程,不能调用两次start方法
第二种:
定义一个实现Runnable接口的类A,
创建A类对象aa,
利用aa构造一个Thread对象tt ,(Thread中的一个构造方法public Thread(Runnable r))
Thread tt = new Thread(aa);
调用tt中的start方法.
注意:Runnable接口中只有一个void run()方法
Thread类中的常用方法
public final void setName(Sting name)设置当前线程的名字
public static Thread currentThread()返回对当前正在执行的线程的对象的引用 public final String getName()返回当前线程的名字
线程的控制:
线程的三个状态:就绪状态,运行状态,阻塞状态
线程控制的基本方法
isAlive()判断线程是否还未终止(三个状态都是活着)
getPriority()获得线程的优先级
setPriority()设置线程的优先级
Thread.sleep()让当前线程睡眠指定毫秒(由运行到阻塞)
join()调用某线程的该方法,将当前线程与该线程合并,即等待该线程结束,再恢复当前线程的运行
yield()让出cpu,当前线程进入就绪队列等待调度(由运行到就绪)
wait()当前线程进入对象wait pool
notify()/notifyAll() 唤醒对象的wait pool中的一个/所有等待进程
线程的优先级:
线程的优先级从1到10,主线程的缺省优先级是5,子线程的优先级默认和其父线程相同 java提供一个线程调度器监控程序启动后进入就绪状态的所有线程,按线程优先级决定执行顺序
Thread.MIN_PRIORITY = 1
Thread.NORMAL_PRIORITY = 5
Thread.MAX_PRIORTIY = 10
获得和设置线程对象的优先级
int getPriority();
void setPriority(int newPriority)
通常优先级高的线程先于优先级低的线程执行,但不总是这样,实际开发中并不单纯依赖优先级来决定线程运行次序
线程的休眠:
暂停执行当前运行的线程,使之进入阻塞状态,经过指定的延迟时间后再醒来并进入到就绪状态
Thread类提供的方法
public static void sleep(long millis)
public static void sleep(long millis, int
会抛出InterruptedException异常,必须用try catch捕获子类继承Thread类或实现Runnable接口的run方法都不能抛出异常
为何会堵塞
堵塞状态是前述四种状态中最有趣的,值得我们作进一步的探讨。线程被堵塞可能是由下述五方面的原因造成的:
调用 sleep(毫秒数),使线程进入“睡眠”状态。在规定的时间内,这个线程是不会运行的。
用 suspend()暂停了线程的执行。除非线程收到 resume() 消息,否则不会返回“可运行”状态。
用 wait()暂停了线程的执行。除非线程收到 nofify() 或者 notifyAll()消息,否则不会变成“可运行”
线程正在等候一些 IO(输入输出)操作完成。
线程试图调用另一个对象的“同步”方法,但那个对象处于锁定状态,暂时无法使用。
死锁:
由于线程可能进入堵塞状态,而且由于对象可能拥有“同步”方法——除非同步锁定被解除,否则线程不能访问那个对象——所以一个线程完全可能等候另一个对象,而另一个对象又在等候下一个对象,以此类推。
这个“等候”链最可怕的情形就是进入封闭状态——最后那个对象等候的是第一个对象!此时,所有线程都
会陷入无休止的相互等待状态,大家都动弹不得。我们将这种情况称为“死锁”。尽管这种情况并非经常出
现,但一旦碰到,程序的调试将变得异常艰难。
线程的让步:
让出cpu,给其他线程执行的机会
运行中的线程主动放弃当前获得cpu处理的机会,进入就绪状态
public static void yield()
线程的串行化:
在多线程程序中,如果一个线程运行的过程用到了另一个线程的运行结果,则可以进行线程的串行化处理
public final void join() throws InterruptedException
t.join()暂停执行t.join()的这个线程,等待t线程运行完毕,这个线程才会获得继续执行的机会
线程的同步:
synchronized关键字
synchronized可以修饰一个方法或方法内的某个代码块
synchronized修饰代码块
格式:
synchronized(随便一个类对象名aa)
{
同步代码块
}
说明:
判断aa是否被其他线程霸占,如果发现已霸占,当前线程等待,如果没有被霸占当前线程霸占aa对象,执行同步代码块,执行完自动释放对aa的霸占,线程再次竞争对aa的霸占,cpu会选择一个线程霸占aa
结果:一个线程操作某资源时,不允许其他线程操作该资源,即一次只允许一个线程处理该资源
synchronized修饰方法:
synchronized修饰方法时,实际霸占的是该方法的this指针所指向的对象,即正在调用该方法的对象
霸占的专业术语叫锁定,霸占住对象专业术语叫监听器
疑:买票程序用expends thread方法能不能把类里要锁定的字符串设置为数据区的字符串|String str = "aaa";不加static
<span style="font-size:18px"><span style="font-family:SimSun">class A implements Runnable
{
public int ticket = 100;
String str = new String("哈哈");
public void run()
{
String str = "哈哈";
while(true)
{
synchronized(str) // // synchronized 保证了当前线程没执行完13行到23行的代码时,其它线程不能访问该代码
{
if(ticket > 0)
{
System.out.printf("%s线程正在卖出第%d张票\n",Thread.currentThread().getName(),ticket);
--ticket;
}
else
{
break;
}
}
}
}
}
public class TestTickets_8
{
public static void main(String[] args)
{
A aa = new A();
Thread t1 = new Thread(aa);
t1.start();
Thread t2 = new Thread(aa);
t2.start();
}
}</span></span>