您的位置:首页 > 编程语言 > Java开发

java多线程及安全问题

2012-12-06 11:18 302 查看
进程:是一个正在执行中的程序。

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

线程:就是进程中的一个独立的控制单元。

线程在控制着进程的执行。

通过对api的查找,java已经提供了对线程这类事物的描述,就是Thread类

1.创建线程的第一种方式:继承Thread类。

步骤:

1.定义类继承Thread类

2.复写Thread类中的run方法。

目的:将自定义代码存储在run方法,让线程运行。

3.调用线程的start方法,启动线程,调用run方法。

class Demo extends Thread

{

//run()方法为线程的主要方法,所要依赖线程运行的代码都要在这个函数里运行

public void run()

{

//多线程运行的代码块

}

}

main(String args[])

{

//创建Thread子类对象的同时,线程也被创建了。

Demo d = new Demo();

//用start方法开启线程,执行Demo类中的run方法。

d.start();

//如果调用run方法,就仅仅是调用了Demo类中run方法,并未启动新的线程

d.run();

}

各种方法的作用:

sleep(time) 使线程冻结一段时间,时间到后线程自动运行;

wait() 使线程暂停,等待notify() 方法唤醒后线程方可继续运行;

stop() 结束当前线程。

例子:多个窗口同时卖票。

利用第一种创建线程的方式实现卖票

class Ticket extends Thread{

//利用静态成员变量共享票数。但是静态变量比较耗费资源。

private static int tick = 100;

public void run(){

while(true){

if(tick>0){

System.out.println(Thread.currentThread().getName()+": "+tick--);

}

}

}

}

public static void main(String args[]){

Ticket t1 = new Ticket();

Ticket t2 = new Ticket();

Ticket t3 = new Ticket();

Ticket t4 = new Ticket();

t1.start();

t2.start();

t3.start();

t4.start();

}

2.创建线程的第二种方式:实现Runable接口

步骤:

1.定义类实现Runnable接口

2.覆盖Runnable接口中的run方法。

将线程要运行的代码存放在该run 方法中。

3.通过Thread类建立线程对象。

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

为什么要将Runnable接口的子类对象传递给Thread的构造函数。

因为,自定义的run方法所属的对象时Runnable节后的子类对象。

所以要让线程去指定指定对象的run方法,就必须明确该run方法所属对象。

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

售票例子:

class Ticket implements Runnable{

private int tick = 100;

public void run(){

while(true){

if(tick>0){

System.out.println(Thread.currentThread().getName()+": "+tick--);

}

}

}

}

public static void main(String args[]){

//与上面的售票相比,实现票数共享是通过只创建一个Runnable子类对象来实现

//将此对象通过多个线程来运行,以达到多线程效果。

Ticket t1 = new Ticket();

new Thread(t1).start();

new Thread(t2).start();

new Thread(t3).start();

new Thread(t4).start();

}

实现方式和继承方式有什么区别呢?(面试常考)

现方式好处:避免了单继承的局限性。

在定义线程时,建议使用实现方式。

java机制只允许继承一个父类,但是可以实现多个接口,有的时候一个子类需要继承父类

但同时又需要被多线程执行时,就不可能再继续用继承Thread类的方式实现多线程了,

只能通过实现Runnable 接口来实现多线程。

多线程安全问题:

问题的原因:

当多条哦语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完。

另一个线程参与进来执行,导致共享数据的错误。

解决办法:

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

同步代码块。

synchronized(对象){

//需要被同步的代码

}

对象如同锁,持有锁的线程可以在同步中执行。

没有持有锁的线程即使获取cpu执行权,也进不去,因为没有获取锁。

同步的前提:

1.必须要有两个或者两个以上的线程。

2.必须是多个线程使用同一个锁

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

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

如何找问题:

1.明确哪些代码是多线程运行代码。

2.明确共享数据。

3.明确多线程运行代码中哪些语句是操作共享数据的。

同步有两种形式:

1.同步代码块 : synchronized(对象){

//需要被同步的代码

}

2.同步函数 : 把synchronized作为修饰符放在函数上,此函数就具备了同步的特性。

同步函数用得到是哪一个锁呢?

函数需要被对象调用,那么函数都有一个所属对象引用,就是this。

所以同步函数使用的锁是this。利用如下代码验证:

private int tick = 100;

public void run(){

if(flag){

while(true){

synchronized(this/*此处未为验证精髓*/){

//同步代码块

if(tick>0){

try{Thread.sleep(10);}catch(Exception e){}

System.out.println(Thread.currentThread().getName()+"..code.."+tick--)

}

}

}

}else

while(true)

show();

}

public synchronized void show(){

//需要同步的内容

if(tick>0){

try{Thread.sleep(10);}catch(Exception e){}

System.out.println(Thread.currentThread().getName()+"..show.."+tick--)

}

}

//通过观察输出票数是否安全便可知道,同步函数的锁是否是this

public void main(String args[]){

new Thread(对象).run();

//让线程等待10ms,以便确认0线程已进入代码块

try{Thread.sleep(10);}catch(Exception e){}

flag=false;

new Thread(对象).run();

}

静态同步函数,使用的锁是什么呢?

通过验证,不是this,因为静态方法中也不可以定义this。

静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。

类名.class 该对象的类型是Class ,所使用的锁是该方法所在类的字节码文件对象。

(重点)单例设计模式:

饿汉式:

class Single{

//先创建对象,需要的时候直接调用

private static final Single s = new Single();

//将构造函数私有化,禁止外界的访问。

private Single(){}

public static Single getInstance(){

return s;

}

}

懒汉式:

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;

}

}

死锁:例子:

public void run(){

if(flag){

while(true){

synchronized(MyLock.locka){

Syste.out.printlnt("if locka");

synchronized(MyLock.lockb){

Syste.out.printlnt("if lockb");

}

}

}

}else{

while(true){

synchronized(MyLock.lockb){

Syste.out.printlnt("else lockb");

synchronized(MyLock.locka){

Syste.out.printlnt("else locka");

}

}

}

}

}

class MyLock {

public static Object locka=new Object();

public static Object lockb=new Object();

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