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

java学习笔记多线程学习总结(上)

2015-09-21 20:14 375 查看
一、进程的简述

1、进程:
是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。Java中主线程要运行的代码在main中存储,自定义线程存在run中。
2、线程:
就是进程中的一个独立的控制单元,线程在控制着进程的执行。一个进程中至少有一个线程。
Java jvm启动时会有一个进程java.exe。该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中该线程称之为主线程。
3、扩展:
其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回事机制的线程。
4、多线程存在的意义:
使程序的部分产生同时运行效果,提高效率。

二、创建进程

1、如何在自定义的代码中,自定义一个线程呢?

继承Thread类,重写run()方法。创建步骤:
1、定义类继承Thread

2、复写Thread类中的run方法(目的是:将自定义代码存储在run方法,让线程运行)
3、调用线程的start方法,该方法有2个作用:启动线程、调用run方法。
eg:class Demo extends Thread // 定义一个线程类
{
public void run() // 重写run方法
{
for(int x=0;x<60;x++) // 循环的目的是让线程多运行一会。
System.out.println(“demo run--”+x);
}
}
class ThreadDemo
{
public static void main(String[] args)
{
Demo d = new Demo(); // 建立好一个对象其实就是实例创建一个线程
d.start(); // 线程启动
for(int x=0;x<60;x++)
System.out.println(“Hello world!..”+x); // 主线程
}
}
2、实现Runnable接口,覆写run方法。详细步骤:

1、定义类实现Runable接口。
2、覆盖Runable接口中的run方法。将线程要运行的代码放在该run方法中。
3、通过Thread类建立线程对象。
4、将Runable接口的子类对象作为实际参数传递给Thread类的构造函数(为什么要将Runable 接口的子类对象传 递给Thread的构造函数)因为,自定义的run方法所属的对象是Runable接口的子类对象,所以要让线程去指
定指定对象的run方法。就必须明确该run方法所属对象。
5、调用Thread类的start方法,开启线程,并调用Runable接口子类的run方法。

eg:classTicket implements Runnable // (extendsThread) // 定义类实现Runnable接口用于创建线程

{

private void run() // 实现run方法

{

while(true)

{

if(ticket>0) // 票数大于0时出票

{ System.out.println(Thread.currentThread().getName()+”…sale:”+tick--); }

}

}

}

class TicketDemo

{

public static void main(String[] args)

{

Ticket t = new Ticket();

Thread t1 = new Thread(t); // 创建两个个线程,参数是实现接口的类对象。

Thread t2 = new Thread(t2);

t1.start(); // 启动线程

t2.start();

}

}

3、实现方式和继承方式的区别?
1、实现方式的好处,避免了单继承的局限性。在定义线程时,建立使用实现方式。
2、继承Thread:线程代码存放Thread子类run方法中,实现Runable,线程代码存在接口的子类的run方法。

注:发现程序运行结果每一次都不同,以newi多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行(多核除外)cpu做着快速的切换,以达到看上去是同时运行的效果。我们可以形象地把多线程的运行认为在互相抢夺cpu的执行权。这就是多线程的一个特性:随机性,谁抢到谁执行。至于执行多长时间,Cpu说的算。

三、线程的四种常见状态:
1、New(新创建)
2、Runnable(可运行)
3、Blocked(被阻塞)
4、Waiting(等待)
5、Timed waiting(计时等待)
6、Terminated(被终止)

四、线程的方法介绍

1、staticThread currentThread(); 返回当前正在执行的线程对象。静态方法
2、getName(); 获取线程名称。
3、设置线程名称:setName或者构造函数。调用父类构造super(name);

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

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

Java对于多线程的安全问题提供了专业的解决方式:同步代码块。
同步代码块的格式:Synchronized(对象){ 需要被同步的代码 }
说明:那些语句要操作共享数据,那些语句就需要同步。
eg:class Ticket implements Runnable
{
private int tick = 100;
Object obj = new Object();
public void run()
{
while(true)
{
Synchronized(obj)
{
if(tick>0)
{
try{Thread.sleep(10);} // 停止10秒看效果
catch(Exception e)
{ }
System.out.println(Thread.currentThread().getName()+”..sale:”+tick--);
}
}
}
}
}
同步代码块的对象参数相当于锁,持有锁的线程可以在同步中执行,没有持有锁的线程即便获取cpu的执行权,也进不去,因为没有获取锁。
同步的前提:
1、必须要有2个或2个以上的线程。
2、多个(必须)多个线程使用同一个锁(必须保证同步中只能有一个线程在运行)
同步代码块的好处:解决了多线程的安全问题。
同步代码块的弊端:多个线程需要判断锁,较为消耗资源。

如何找出同步问题:
1、明确哪些代码是多线程运行代码(run中代码及run中调用代码)
2、明确共享数据。
3、明确多线程运行代码中哪些语句是操作共享数据的。
同步有2种表现形式:同步代码块和同步函数。

同步函数封装的定要是需要同步的语句(例如while循环不能放)

同步代码块封装代码,唯一的区别是他带着同步性,若让函数具备同步性,就可以。

六、同步锁

同步函数用的是哪一个锁?
函数需要被对象调用,那么函数都有一个所属对象引用就是this,所以同步函数的使用锁是this。证明实例如下:

class Ticket implements Runnable

{

private int tick = 1000;

Booleanflag = true;

public void run()

{

if(flag)

{

while(true)

{

Synchronized(this)

{

if(tick>0)

{

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

}

else

while(true)

(this.)show();

}

System.out.println(Thread.currentThread().getName()+”…sale:”+tick--);

}

}

}

}

class ThisLockDemo

{

public static void main(String[] args)

{

Ticket t = new Ticket();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

t1.start(); // 一线程开始用同步代码块

t.flag = false; // 二线程开始用同步函数

t2.start();

}

}

如果同步函数被静态修饰后,使用的锁是什么呢?
通过验证发现不是this,因为静态方法中也不可以定义this。
静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。就是类名.class。该对象的类型是class(可以通过getClass()方法获取)。静态的同步方法使用的锁是该方法所在类的字节码文件对象,类名.class。且此对象在内存中是唯一的。

七、死锁
死锁,同步嵌套同步。在编写程序过程中要尽量避免死索。

创建一个死锁程序的例子:

class Test implements Runnable

{

private Boolean flag;

Test(Boolean flag)

{ this.flag = flag; }

public void run()

{

if(flag)

{

while(true)

{

Synchronized(MyLock.locka)

{

System.out.println(“if locka”);

Synchronized(MyLock.Lockb)

{ System.out.println(“if lockb”); }

}

}

}

else

{

Synchronized(MyLock.lockb)

{

System.out.println(“else lockb”);

Synchronized(MyLock.locka)

{

System.out.println(“elselocka”);

}

}

}

}

}

class MyLock

{

static Object locka = new Object();

static Object lockb = new Object();

}

class DeadLockTest

{

public static void main(String[] args)

{

Thread t1 = new Thread(new Test(true)); Thread t2 = new Thread(new Test(false));

t1.start(); t2.start();

}

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