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

学习笔记-java线程

2015-01-06 23:05 176 查看
进程:指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。

线程:指进程中的一个执行流程,是程序内部的控制流程,一个进程中可以运行多个线程。

进程与线程的关系

进程每个程序都至少有一个进程,每个进程中都至少有一个线程。
线程是进程的一个实体。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。线程自己基本上不拥有系统资源。

tips:线程就是程序的执行路径。进程就是来管理这些线程的(线程需要的资源需要从进程获取)。

1. 线程的启动

JAVA程序启动时,会有一个由主方法(main)来定义的线程。这个线程帮助我们的程序依据主函数中的语句顺序执行代码。

我们可以通过java.lang.Thread或者java.lang.Runnable来启动一个线程。

扩展java.lang.Thread类

此类继承Thread类,并重写run()方法。
在实例化线程时,直接new一个对象即可。
启动线程时,调用对象的start()方法。
public class MyThread extends Thread {

public MyThread(){
}

@Override
public void run() {
for(int i=0;i<MainTest.COUNTNUM;i++){
System.out.println("run!!!"+i);
}
}
}


实现java.lang.Runnable接口

此类继承Runnable接口,同样需要重写run()方法。
实例化时,需要调用Thread中带有Runnable 的构造方法,创建对象。
启动线程时,调用对象的start()方法。

public class MyRunnable implements Runnable {

@Override
public void run() {
for(int i=0;i<MainTest.COUNTNUM;i++){
System.out.println("runnable!!!"+i);
}
}
}
新建一个main函数来启动线程

public class MainTest {
static final int COUNTNUM = 1000 ;

public static void main(String[] args) {
//线程启动方法1:
//创建一个Thread类的子类的对象
MyThread t1 = new MyThread() ;
t1.start() ;
//线程启动方法2:
//创建一个实现了Runnable接口的类的对象
MyRunnable r1 = new MyRunnable() ;
//调用Thread带有Runnable的构造器创建Thread对象
Thread t2 = new Thread(r1) ;
t2.start() ;

for(int i=0;i<COUNTNUM;i++){
System.out.println("mainrun!!"+i) ;
}
}
}
三个线程会同时抢夺cpu运行,但输出结果并不一定。

2. 线程优先级

线程存在优先级,优先级范围在1~10之间,默认优先级为5。

因为线程调度优先级操作是没有保障的,只能把线程优先级作用作为一种提高程序效率的方法,但是要保证程序不依赖这种操作。

t1.setPriority(8)
设置优先级为8

3. 线程让步

Thread.yield()方法:暂停当前正在执行的线程对象,并执行其他线程。

yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。

使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。

4. join()方法

等待指定线程执行完毕。(相当于与执行线程合并):线程A和线程B,线程A调用join方法,则在线程A执行完毕之前,线程B不能工作。

5. 休眠

线程休眠的目的是使线程让出CPU的最简单的做法之一,线程休眠时候,会将CPU资源交给其他线程,以便能轮换执行,当休眠一定时间后,线程会苏醒,进入准备状态等待执行。

sleep():休眠,指定的时间(毫秒)或者(毫秒,纳秒)

6. 线程同步

线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。

只能同步方法,而不能同步变量和类
每个对象只有一个锁
不必同步类中所有的方法,类可以同时拥有同步和非同步方法
如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放
如果线程拥有同步和非同步方法,则非同步方法可以被多个线程自由访问而不受锁的限制
线程睡眠时,它所持的任何锁都不会释放
线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁
同步损害并发性,应该尽可能缩小同步范围。同步不但可以同步整个方法,还可以同步方法中一部分代码块
在使用同步代码块时候,应该指定在哪个对象上同步,也就是说要获取哪个对象的锁

public class SynTest {

public static void main(String[] args) {
//创建银行对象
Bank b = new Bank();
//
Thread t1 = new MThread("A", b);
Thread t2 = new MThread("B", b);
//
t1.start();
t2.start();
}
}

/**
* 银行类
*/
class Bank {
int money = 3000;

/**
* 取钱的方法
*/
public void getMoney(String name, int money) {
synchronized (this) {
if (this.money >= money) {
//
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money -= money;
System.out.println(name + "取出" + money + ",剩余:" + this.money);
} else {
System.out.println("余额不足!");
}
}
}
}

/**
* 线程
*/
class MThread extends Thread {
Bank b;

MThread(String name, Bank b) {
super(name);
this.b = b;
}

@Override
public void run() {
b.getMoney(getName(), 2000);
}
}
例:A和B去银行取钱,银行里存有3000,每人次去取2000,为保持结果的合理性,每次只能有一个线程在访问,使用synchronized关键字完成同步。

死锁示例

public class DeadSynTest {
Object syn1 = new Object();
Object syn2 = new Object();
//线程1,那syn1抢syn2
Runnable dst1 = new Runnable(){
@Override
public void run() {
try {
test1();
} catch (Exception e) {
e.printStackTrace();
}
}
};
//线程1,那syn2抢syn1
Runnable dst2 = new Runnable(){
@Override
public void run() {
try {
test2();
} catch (Exception e) {
e.printStackTrace();
}
}
};

/**
* main
* */
public static void main(String[] args) {
//
new DeadSynTest().start() ;
}
public void start(){
new Thread(dst1).start() ;
new Thread(dst2).start() ;
}

/**
* 在test1中拿着syn1的锁去抢syn2的锁
* */
public void test1() throws Exception {
synchronized (syn1) {
System.out.println(Thread.currentThread().getName() + "test1");
Thread.sleep(1000);
synchronized (syn2) {
System.out.println(Thread.currentThread().getName() + "test2");
Thread.sleep(1000);
}
}
}

/**
* 在test2中拿着syn2的锁去抢syn1的锁
*/
public void test2() throws Exception {
synchronized (syn2) {
System.out.println(Thread.currentThread().getName() + "test2");
Thread.sleep(1000);
synchronized (syn1) {
System.out.println(Thread.currentThread().getName() + "test1");
Thread.sleep(1000);
}
}
}
}
两个线程被阻塞,形成线程死锁

7. 线程交互

wait():导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法。
notify():唤醒在此对象监视器上等待的单个线程
notifyAll():唤醒在此对象监视器上等待的所有线程

tips:必须从同步环境内调用wait()、notify()、notifyAll()方法。线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: