您的位置:首页 > 职场人生

黑马程序员-----多进程

2015-08-20 16:10 609 查看
——- android培训java培训、期待与您交流! ———-

1、 进程、线程、多线程的区别:

1)进程:是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该循序是一个执行路径,或叫控制单元。

2)线程:是进程中的一个独立的控制单元,线程在控制着进程的执行。

3)多线程:一个进程中可以有多个执行路径。

注意:一个进程中至少要有一个线程。

JVM启动时启动了多条线程,至少有两个线程可以分析的出来:

1.执行main函数的线程,该线程的任务代码都定义在main函数中。

2.负责垃圾回收的线程。

2、 创建线程的两种方法:

第一种方法:继承Thread类。

步骤:1)定义类继承Thread类

2)复写Thread类中的run方法

3)直接创建Thread的子类对象创建线程

4)调用线程的start方法(作用:启动线程;调用run方法)

class MyThread extends Thread
{
public void run()
{
//要在线程中执行的代码
for(int i=0;i<100;i++)
System.out.println("MyThread:"+i);
}
}


第二种方法:实现Runnable接口。

步骤:1)定义类实现Runnable接口

2)覆盖Runnable接口中的run方法

3)通过Thread类建立线程对象

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

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

class MyThread1 implements Runnable
{
public void run()
{
//要在线程中执行的代码
for(int i=0;i<100;i++)
System.out.println("MyThread:"+i);
}
}


完整代码示例演示:

package com.shan;
/**需求:建立一个多线程
* @param args
*/
public class Demo37 {
public static void main(String[] args)
{
System.out.println("启动主线程");
//启动第一个线程
Thread t1=new MyThread();
System.out.println("启动第一个线程");
t1.start();

//启动第二个线程
MyThread1  mt=new MyThread1();
Thread  t2=new Thread(mt);
System.out.println("启动第二个线程");
t2.start();

}

}
class MyThread extends Thread //创建线程的第一种方式
{
public void run()
{
//要在线程中执行的代码
for(int i=0;i<100;i++)
System.out.println("MyThread:"+i);
}
}
class MyThread1 implements Runnable  //创建线程的第二种方式
{
public void run()
{
//要在线程中执行的代码
for(int i=0;i<100;i++)
System.out.println("MyThread1:"+i);
}
}


3、 实现方式和继承方式有什么区别?(重点)

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

2) 线程代码存放的位置不一样

继承Thread类:线程代码存放在Thread子类的run方法中。

实现Runnable接口:线程代码存放在接口的子类的run方法中

4、 线程都有自己默认的名称。Thread-编号(该编号从0开始)

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

getName():获取线程名称

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

5、线程安全问题产生的原因:

1.多个线程在操作共享的数据。

2.操作共享数据的线程代码有多条。

当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。

解决方案:

1)同步代码块:(java对于多线程的安全问题提供了专业的解决方式,就是同步代码块)

格式:synchronized(对象)
{需要被同步的代码;}


2) 同步函数:

格式:在函数上加上synchronized修饰符即可。


示例演示:模拟4个线程同时卖100张票

package com.shan;
/**
* 需求:模拟4个线程同时卖100张票。
* @author ling
*
*/
public class Demo38 {

public static void main(String[] args)
{
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();
}

}
class Ticket implements  Runnable
{
private int num =1000;
Object obj=new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
if(num>0)
{
System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
}
}
}
}
}


6、 同步的前提:

1) 必须要有两个或两个以上的线程;

2) 必须保证同步中只有一个线程在运行;

好处:解决了多线程的安全问题

弊端:多个线程需要判断锁,较为消耗资源。

7、 同步有两种表现形式:

一种是同步代码块;一种是同步函数

8、 同步函数使用的锁是this静态的同步函数使用的锁是该方法所在类的字节码文件对象,即:类名.class

示例演示:储户,两个,每个都到银行存钱,每次存100,共存三次。

classBank{
privateintsum;
publicsynchronizedvoidadd(intnum){//同步函数
sum=sum+num;
System.out.println("sum="+sum);
}
}
classCusimplementsRunnable{
privateBankb=newBank();
publicvoidrun(){
for(intx=0;x<3;x++){
b.add(100);
}
}
}

classBankDemo{
publicstaticvoidmain(String[]args){
Cusc=newCus();
Threadt1=newThread(c);
Threadt2=newThread(c);
t1.start();
t2.start();
}
}


单例模式中的懒汉式就用到了同步函数

class Single{
private static Single s = null;
private Single(){}
public static Single getInstance(){
if(s ==null){
synchronized(Single.class){
if(s == null)
s = new Single();
}
}
return s ;
}
}


9、 死锁:同步中嵌套同步,就出现死锁现象。

10、线程间的通信:(等待唤醒机制)

1)操作线程的方法有:wait()/notify()/notifyAll();

为什么这些操作线程的方法要定义在Object类中呢?

分析:因为这些方法在操作同步中的线程时,都必须要标识它们所操作线程特有的锁,只有同一个锁上的被等待线程可以被同一个锁上的notify唤醒,不可以对不同锁中的线程唤醒。也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。

2) wait()和sleep()有什么区别?

分析:wait():释放资源释放锁,没有执行权。

sleep():释放资源不释放锁,有执行权。

示例演示:生产者—消费者

class Resource{
private String name ;
private String sex ;
private boolean flag = false;

public synchronized void set(String name,String sex){
if(flag )
try{
this.wait();
} catch(InterruptedException e){
e.printStackTrace();
}
this.name = name;
this.sex = sex;
flag = true ;
this.notify();
}

public synchronized void out(){
if(!flag )
try{
this.wait();
} catch(InterruptedException e){
e.printStackTrace();
}
System. out.println(name + "..." + sex);
flag = false ;
this.notify();
}
}
class Input implements Runnable{
Resource r;
Input(Resource r){
this.r = r;
}

public void run(){
int x = 0;
while(true ){
if(x == 0){
r.set( "mike","男" );
} else{
r.set( "lili","女" );
}
x = (x + 1)%2;
}
}
}

//输出
class Output implements Runnable{
Resource r;

Output(Resource r){
this.r = r;
}

public void run(){
while(true ){
r.out();
}
}
}

class ResourceDemo {
public static void main(String[] args){
//创建资源
Resource r = new Resource();
//创建任务
Input in = new Input(r);
Output out = new Output(r);
//创建线程,执行路径
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
//开启线程
t1.start();
t2.start();
}
}


11、 停止线程

1) 定义循环结束标记。

因为线程运行代码一般都是循环,只要控制了循环即可。

2) 使用interrupt(中断)方法

该方法是结束线程的冻结状态,是线程回到运行状态中来。

总结:如何停止线程?

只有一种,run方法结束。 开启多线程运行,运行代码通常是循环结构。 只要控制住循环,就可以让run方法结束,也就是线程结束。

12、 守护线程

setDaemon()方法是将该线程标记为守护线程或用户线程(后台线程)。当正在运行的线程都是守护线程时,java虚拟机自动退出。

该方法必须在启动线程前调用。

判断是否是后台线程:使用Thread对象的isDaemon()方法;

例如:

StopThread  st=new  StopThread  ();
Thread  t1=new Thread  (st);
Thread  t2=new Thread  (st);
t1.setDaemon(true);      //如果为true,则表示将该线程标记为守护线程
t2.setDaemon(true);
t1.start();
t2.start();


13、 join方法:

调用join方法的线程对象强制运行,该线程强制运行期间,其他线程无法运行,必须等到该线程结束后其他线程才可以运行。

join方法的重载方法:
join(long millis):
join(long millis,int nanos):


14、 线程的优先级:

每个线程都有优先级,优先级的高低只和线程获得执行机会的次数多少有关。

并非线程优先级越高的就一定先执行,哪个线程的先运行取决于CPU的调度;

默认情况下main线程具有普通的优先级,而它创建的线程也具有普通优先级。

Thread对象的setPriority(int x)和getPriority()来设置和获得优先级。
MAX_PRIORITY    :   值是10
MIN_PRIORITY    :   值是1
NORM_PRIORITY   :   值是5(主方法默认优先级)


15、 线程让步:(yield)

暂停当前正在执行的线程对象,把执行机会让给相同或更高优先级的其他线程,让线程可以你一个我一个的进行交替执行。

——- android培训java培训、期待与您交流! ———-
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: