进程
每个独立执行的程序都是一个进程。
1、程序(任务)的执行过程 --->动态性
2、持有资源(共享内存,共享文件)和线程
例如:
进程:执行QQ
线程:在QQ上可以聊天,收发文件,
线程
是系统中最小的执行单元,一个进程中可以有多个线程,线程共享进程的资源
线程的交互:互斥,同步
Java对线程的支持,线程的创建和启动,线程常用方法,如何停止线程:
继承class Thread方法(java.lang) | 实现interface Runnable接口(java.lang) |
构造方法,run()方法 | run()方法 |
start()方法,启动线程 sleep()方法,线程休眠 join()方法,使其他线程等待当前线程终止 yield()方法,当前运行线程释放处理器资源 | |
获取线程引用,static Thread currentThread(),返回当前运行线程的引用 |
多线程:指一个应用程序中,有多条并发执行的线索,每条线索都被称为一个线程。他们会交替执行,彼此之间可以进行通信。
继承Thread:
重写Thread类中的run方法,并且调用start方法用于启动线程。
package com.buaa.test;
public class MyThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
System.out.println("MyThrerad中的run方法");
}
}
}
package com.buaa.test
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
while(true){
System.out.println("main方法中的线程在运行");
}
}
}
实现Runnable接口:
可以实现资源的共享。
适合多个相同程序代码的线程去处理同一个资源的情况。
可以避免java单继承的局限性。
package com.buaa.test2;
public class PrivateThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
System.out.println("这里是私人的线程啊......");
}
}
}
package com.buaa.test2;
public class Test2 {
public static void main(String[] args) {
PrivateThread pThread = new PrivateThread();
Thread thread = new Thread(pThread);
thread.start();
while(true){
System.out.println("main方法中的线程啊.....");
}
}
}
将某个线程设置成为后台线程:
在某个线程启动之前,就要将其设置为后台线程。即setDaemon()方法必须在start()方法之前调用。
进程中只有后台线程运行时,进程就会结束。但是只要有一个前台线程在运行,这个进程就不会结束。
package com.buaa.test3;
public class DaemonThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
System.out.println(Thread.currentThread().getName()+"------is running.");
}
}
}
package com.buaa.test3;
public class Test3 {
public static void main(String[] args) {
DaemonThread dThread = new DaemonThread();
Thread thread =new Thread(dThread,"后台线程");
thread.setDaemon(true); //将thread线程设置成为后台线程
thread.start();
}
}
线程的生命周期:
阻塞原因:等待同步锁,调用IO阻塞方法,调用wait()方法(需要noyify方法唤醒),调用jion()方法,调用sleep()方法。
线程的调度:
java虚拟机按照特定的机制为程序中的每个线程分配CPU的使用权。
线程的调度模型:
优先级用1---10之间的整数来表示,数字越大,优先级越高。
可以用Thread中的setPriority(int newPriority)来设置,
也可以用Thread的静态常量来表示:
package com.buaa.test4;
public class MinPriority implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0 ;i < 10 ;i++){
System.out.println(Thread.currentThread().getName()+"正在输出:"+i);
}
}
}
package com.buaa.test4;
public class MaxPrority implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0 ;i < 10 ;i++){
System.out.println(Thread.currentThread().getName()+"正在输出:"+i);
}
}
}
package com.buaa.test4;
public class Test4 {
public static void main(String[] args) {
Thread maxThread = new Thread(new MaxPriority(),"高优先级");
Thread minThread = new Thread(new MinPriority(),"低优先级");
maxThread.setPriority(10);
minThread.setPriority(Thread.MIN_PRIORITY);
maxThread.start();
minThread.start();
}
}
线程休眠:
静态方法:sleep(long millis),程序会进入休眠等待状态
package com.buaa.test5;
public class SleepThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0 ; i < 10;i++){
if(i==3){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("线程正在输出:"+i);
}
}
}
package com.buaa.test5;
public class Test5 {
public static void main(String[] args) {
Thread thread = new Thread(new SleepThread());
thread.start();
}
}
线程让步:
通过yield()方法来实现。和sleep()方法一样,都可以让当前线程进入线程暂停,但是yield方法不会阻塞线程,只会让线程转换成就绪状态。当某个线程yield之后,只有和这个线程相同优先级或者是更高的优先级才会获得执行机会。
package com.buaa.test6;
public class YieldThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0 ;i <5 ;i++){
System.out.println(Thread.currentThread().getName()+"---------"+i);
if(i==3){
System.out.println("线程让步:");
Thread.yield();
}
}
}
}
package com.buaa.test6;
public class Test6 {
public static void main(String[] args) {
Thread t1 = new Thread(new YieldThread(),"线程A");
Thread t2 = new Thread(new YieldThread(),"线程B");
t1.start();
t2.start();
}
}
线程插队:
join()方法。当某个线程中调用其他线程的join()放法时,调用的线程将被阻塞,直到被join()方法加入的线程执行完成后才会继续运行。
join()方法。当某个线程中调用其他线程的join()放法时,调用的线程将被阻塞,直到被join()方法加入的线程执行完成后才会继续运行。
package com.buaa.test7;
public class EnergencyThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0 ; i < 6 ;i++){
System.out.println(Thread.currentThread().getName()+"输入:"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package com.buaa.test7;
public class Test7 {
public static void main(String[] args) {
Thread t = new Thread(new EnergencyThread(),"插队线程");
t.start();
for(int i = 0 ;i<6 ;i++){
System.out.println(Thread.currentThread().getName()+"输入:"+i);
if(i==2){
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
多线程同步:
多线程去访问同一个资源时,有可能会有安全问题。为此,需要多线程同步,即限制某个资源在同一时刻只能被一个线程访问。
为了实现这种限制,java提供了一种同步机制。当多个线程使用同一个资源时,可以将处理共享资源的代码放在一个代码块中,使用synchronized关键字进行修饰。成为同步代码块。
synchronized(lock){
操作资源
}
lock是锁对象,默认情况下是1。当线程执行同步代码块时,先检查lock标志位,若为1,则可以进入,进入后将编制为置为0。此时外面的新线程会发生阻塞。只有里面的线程出来了,将标志位置1时,新线程才能进入。
同步代码块:
package com.buaa.test8;
public class Ticket1 implements Runnable{
private int ticket = 10;
Object lock = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized (lock) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖出的票"+ticket--);
}else{
break;
}
}
}
}
}
package com.buaa.test8;
public class Test8 {
public static void main(String[] args) {
Ticket1 ticket1 = new Ticket1();
new Thread(ticket1,"线程一").start();
new Thread(ticket1,"线程二").start();
new Thread(ticket1,"线程三").start();
new Thread(ticket1,"线程四").start();
}
}
同步方法:
synchronized 返回值类型 方法名(参数一,参数二){
}
被synchronized修饰的方法某一时刻只能允许一个线程访问,访问该方法的其他线程都会发生阻塞,直到当前线程访问完毕后,其他线程才有机会执行。
package com.buaa.test9;
public class TicketMethod implements Runnable{
private int tickets = 10;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
saleTicket();
if(tickets<=0){
break;
}
}
}
private synchronized void saleTicket() {
// TODO Auto-generated method stub
if(tickets>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖票"+tickets--);
}
}
}
package com.buaa.test9;
public class Test9 {
public static void main(String[] args) {
TicketMethod tMethod = new TicketMethod();
new Thread(tMethod,"线程一").start();
new Thread(tMethod,"线程二").start();
new Thread(tMethod,"线程三").start();
new Thread(tMethod,"线程四").start();
}
}
同步方法也有锁,它的锁是当前调用该方法的对象,也就是this指向的对象。
多线程通信:
在几个线程协同完成工作时,需要线程间的通信。
在几个线程协同完成工作时,需要线程间的通信。
wait()、notify()、notifyAll()方法,解决线程间的通信。
sleep()、yield()和wait()方法的区别
sleep() | yield() | wait() | |
来自于的类 | Thread.sleep(1000); | Thread.yield(); | obj.wait(); |
机理 | 使现在运行的线程暂停。在同步代码块中没有释放锁。是静态方法,只能控制当前正在运行的线程休眠,休眠结束后,会返回到就绪状态。 | 使现在运行的线程暂停。但是不会阻塞该线程,只是将该线程转换成就绪状态,让系统的调度重新调度一次。 | wait()方法释放了同步锁进入等待,直到其他线程进入同步锁,并调用notify()方法唤醒该线程为止 |
适用范围 | 任何地方 | 任何地方 | 同步代码块中,同notify()一起使用 |
异常情况 | 需要捕获异常 | 不需要 | 不需要 |
notify()方法,用于唤醒此同步锁上等待的第一个调用wait()方法的线程。 notifyAll(),唤醒所以等待的线程 |