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

黑马程序员——多线程(一)

2012-05-18 12:43 211 查看
---------------------- android培训java培训、期待与您交流! ----------------------

多线程(一)

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

线程:进程中的一个控制单元。线程控制着进程的执行。

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

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

而且这个线程运行的代码存在于main方法中,该线程称之为主线程。

线程创建方式:

方法一:

 定义Thread类的子类并重写Thread类的run方法;然后创建该线程(生成该子类的对象)。

调用线程的start方法,该方法有两个作用,启动线程,并调用run方法。

class ThreadDemo
{
public static void main(String[] args)
{
MyThread mt = new MyThread();//创建一个线程
mt.start();//启动该线程并运行run方法
mt.run();// 不能直接调用run方法,否则运行多次结果是一样的,相当于普通方法的调用
for(int j=0;j<20;j++) {
System.out.println("main :" + j);
}

}
}

class MyThread extends Thread
{
public void run() {
for(int i=0;i<20;i++) {
System.out.println("run:"+ i);
}
}
}



Thread 类用于描述线程,该类就定义了一个功能,用于存放线程要运行的代码,代码就存放在run方法中。Start方法用于启动线程。

线程都有自己的名称 main方法为主线程 名称是 main 。自定义的线程名称为:Thread-编号 形式 编号从0开始。

也可以通过构造函数创建线程名称,或者setName方法

Thread.currentThread().getName() 可以获取当前线程的名称

class ThreadDemo
{
public static void main(String[] args)
{
MyThread mt1 = new MyThread("thread1");//创建一个线程
MyThread mt2 = new MyThread("thread2");
mt1.start();//启动该线程
mt2.start();

for(int j=0;j<50;j++) {
System.out.println(Thread.currentThread().getName()+" ..main :" + j);
}

}
}

class MyThread extends Thread
{
//利用构造函数来设置线程的名称,也可以用setName方法
public MyThread(String name) {
super(name);
}

public void run() {
for(int i=0;i<50;i++) {
System.out.println(Thread.currentThread().getName()+" run:"+ i);
}
}
}


方法二:

1、自定义类实现Runnable接口

2、重写Runnable接口中的run方法

3、建立Thread类的线程对象

4、将Runnable接口的子类对象作为参数传递给Thread类的构造方法

5、通过调用Thread类的start方法启动线程并调用Runnable接口中的run方法代码

代码如下:

class  TicketDemo
{
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 ticket = 100;

public void run() {
while(true) {
if(ticket>0) {
try{
Thread.sleep(5);//线程睡眠
} catch(Exception e) {
e.printStackTrace();
}

System.out.println(Thread.currentThread().getName()+
" sale:"+ ticket--);
}
}
}
}


实现Runnabel接口和继承Thread类的区别: 

1、实现的好处是避免了单继承的局限性。

2、线程代码存放的位置不一样:继承存放在子类的run方法中,实现存放在接口子类的run方法中。

通常使用实现Runnable接口。

多线程运行的问题:

当多条语句在操作同一个县城共享数据时,一个线程对多条语句至执行力一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。

解决方法:

对于多条操作共享数据的语句,只能让一个线程都执行完,其他线程不可以参与执行。

Java中可以使用同步代码快

格式如下:

synchronized(对象) {

需要被同步的代码.........

}

此处传递的对象如同锁,持有锁的线程可以在同步中执行。没有持有锁的线程即使有cpu的执行权,也进不去。

同步的前提:

1、必须要有两个以上的线程才同步

2、多个线程使用同一个锁

同步解决了安全问题但是也消耗了资源

对上述共享数据代码同步得到:

/*
简单的多个窗口同时售票
*/
class  TicketDemo
{
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 ticket = 200;
Object obj = new Object();

public void run() {
while(true) {
synchronized(obj) {//该对象可以是任意对象
if(ticket>0) {
try{
Thread.sleep(5);
} catch(Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
" sale:"+ ticket--);
}
}

}
}
}


如何找出程序中多线程存在的安全问题:

1、明确哪些代码是多线程运行的代码.(run方法中的代码)

2、明确共享数据(tikcet)

3、明确多线程运行代码中哪些语句是操作共享数据的(对ticket的操作)

也可以对函数进行同步,用synchronized修饰函数即可。

同步函数用的锁是this。

如果同步函数被Static修饰,用的锁是该方法所在类的字节码文件对象,类名.class

 

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