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

黑马程序员---java学习笔记之多线程

2013-12-19 12:07 543 查看
------- android培训java培训、期待与您交流! ----------

1、什么是进程?进程就是系统正在执行中的程序。每一个进程都有一个执行顺序,该顺序是一个执行路径或者说控制单元。

什么是线程?就是进程中的一个独立单元,线程控制着进程的执行。

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

2、jvm启动的时候,有一个java进程,该进程中至少有一个线程负责java程序的执行,该线程称为主线程。

3、jvm虚拟机启动的时候其实是一个多线程。

4、自定义线程方法一:定义一个继承Thread的子类,重写Thread类中的run方法,然后创建对象,调用Thread的start方法。

Thread类中的start方法有两个作用:开启一个线程;调用Thread子类中重写的run方法。

class ThreadTest extends Thread
{
//创建Thread的子类,并重写其run方法
public void run()
{
for( int i = 0; i < 60; i++ )
System.out.println("ThreadTest "+i);
}
}

public class ThreadDemo {

public static void main(String[] args) {
// TODO Auto-generated method stub
//创建子类对象
ThreadTest tt = new ThreadTest();
//调用其run方法
tt.start();

for( int i = 0; i < 60; i++ )
System.out.println("ThreadDemo "+i);

}

}
上述代码为创建自定义线程的示例,多次运行打印输出的结果不同可体现出多线程执行时的随机性,亦即cpu在某一时刻只能执行一个线程,之所以会有多个线程同时执行的感觉,因为cpu执行速度非常地快,它在线程之间做着快速的切换。
5、主线程执行的是main方法中的代码,自定义线程执行的是子类中重写的run方法中的代码。所以你可以把你想在另一个线程中执行的代码写进子类的run方法里。

6、如果你创建了Thread子类对象,但并没有调用start方法,而是直接调用run方法,这样导致的结果是自定义的线程未被开启,只有主线程在调用run方法。

7、线程的状态:

被创建:线程被创建;

运行状态:当调用Thread类中的start方法,开启线程,线程进入运行状态。在这个状态下,线程具有运行资格且有执行权。

阻塞状态:具备运行资格,但是没有执行权;

冻结状态:线程在遇到sleep(time)时,进入睡眠状态,在定时时间到,自动进入阻塞或者运行状态;线程在遇到wai时进入冻结状态,知道由notify唤醒才能够回到阻塞或运行状态。在冻结状态下,线程放弃了运行资格和执行权;

消亡状态:线程遇到stop方法时,进入消亡状态;或者线程代码执行结束,自动进入消亡状态。消亡状态就是线程的结束。

8、一个java进程里可能有许多的线程,在有线程未被执行结束时,该java进程和jvm是不会关闭的。

9、Thread 类有一个静态的currentThread()方法,用于返回当前线程;Thread类中有一个getName()方法和setName()方法,用于获取当前线程的名字或者设置当前线程的名字。

10、已经start过的线程对象不需要再次对它进行start开启。

11、java中真正创建线程对象的是new Thread(或new 其子类)。

12、创建线程的第2种方法:定义类实现Runnable接口并且重写其run方法然后将该类的对象传递给Thread类的构造方法Thread(Runnable r),然后利用该构造方法创建Thread对象。为什么要将Runnable的实现类对象传递给Thread类的构造函数呢?这是为了由Thread创建的线程对象执行Runnable实现类中的run()方法。

class Ticket implements Runnable
{//实现Runnable接口,并重写run方法
private int ticket = 400;
public void run()
{
while(true)
{
if( ticket > 0 )
System.out.println(ticket--);
else
break;
}
}
}

public class ThreadDemo2 {

public static void main(String[] args) {
// TODO Auto-generated method stub

//创建Runnable实现类的对象
Ticket  t = new Ticket()

//创建线程对象的同时将Runnable实现类的对象传递进去
;
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();

}

}
这是视频中售票的例子。
13、创建线程对象的两种方式的区别:

a):继承Thread类去创建线程的类因为java的单继承就不能继承其他的类了,这在该类还需继承其他类的情况下就不太合适了;实现Runnable接口然后传递给Thread相关构造方法的类就可以再继承其他的类;

b):采用继承的方式,其线程运行代码存储在Thread继承子类中;采用实现的方式,其线程运行代码,存储在实现Runnable接口的子类中,存储位置不同。

14、当多个线程执行同一段代码且该代码中设计到共享数据时,有可能会出现共享数据的错误。这时候的一个解决办法就是使用synchronized代码块。

15、使用同步的前提是:

有两个或两个以上的线程;必须是多个线程使用同一个锁(对象)。

16、同步的好处是:解决了多线程的安全问题;弊端是:除带有锁的线程外的其他线程都需要判断锁,耗费了资源,效率可能低一些。

17、同步的表现形式有两种:同步函数和同步代码块。

18、怎么找多线程中的安全问题?

a):首先是找多线程中共同执行的代码;

b):然后是找多线程都会使用到的数据也就是共享数据;

c):最后是明确多线程中哪些数据是操作共享数据的。

19、非静态同步函数的锁是调用该函数的对象this。下面是示例:

class Ticket1 implements Runnable
{
private int tick = 100;
Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(obj)
{
try{Thread.sleep(10);}catch(Exception e){}
if( tick > 0 )
System.out.println(Thread.currentThread().getName()+" "+tick--);
}
}

}
else
while(true)
{
show();
}
}
synchronized void show()
{
try{Thread.sleep(10);}catch(Exception e){}
if( tick > 0 )
System.out.println(Thread.currentThread().getName()+" "+tick--);
}
}

public class ThreadDemo3 {

public static void main(String[] args) {
// TODO Auto-generated method stub

Ticket1 t = new Ticket1();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);

t1.start();
try{Thread.sleep(10);}catch(Exception e){}
t.flag = false;
t2.start();

}

}
上述代码可能会出现0号票的错票,原因是两个线程同步时使用的并不是同一个锁,要避免错误地话,可将同步代码块的锁改为this.
20、静态同步函数的锁是该静态函数所在的字节码文件对象。类型是Class,对象名称是类名.class

21、单例设计模式

a):(复习)单例设计模式有两种,一种是饿汉式,一种是懒汉式。

饿汉式:

private  static final Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
懒汉式:
private  static  Single s = null;
private Single(){}
public static Single getInstance()
{
if(s == null)
s = new Single();
return s;
}
分析可知,当多线程执行到懒汉式的getInstace方法时,容易出现安全问题,导致创建了多个Single对象。所以需要对该方法进行同步。
使用同步函数的方式:

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

这种方式比较低效,为什么?因为每个要调用该getInstance方法的线程都要进行是否含有锁的判断,比较地耗费资源。

使用同步代码块的形式:

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


这种方式只要有线程创建了对象,以后进入的线程就只需要判断外层的if(s == null),而不用再去判断是否含有锁了。

22、死锁现象的原因是:同步中嵌套同步,两个同步的锁不一样。



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: