线程

来源:互联网 发布:电子音乐软件下载 编辑:程序博客网 时间:2024/04/30 04:02
一:Thread
每一个线程都必须通过start()启动
启用多线程一定依靠Thread类完成
start 里面会调用一个 start0 方法,使用了Native声明,
这是一种JNI技术:
特点:使用java调用本机操作系统提供的函数;
缺点:不能够离开特定的操作系统;
如果线程需要执行,需要操作系统分配资源,所以此操作系统严格来讲是由JVM根据不同的操作系统而
实现的。

二:Thread与Runnable
多线程两种方法实现的区别:
通过定义已经清楚了多线程的两种实现方式:
这两种方式的区别:
使用Runnbale 与 Thread 类相比,解决了单继承实现,至少这一点上已经明确,如果要使用,应使用Runnable接口;
发现Thread 实现了Runnable 接口;
使用Runnab接口可以比Thread类更好的实现数据共享,此时的数据共享指的是多个线程访问同一资源的操作。
用Runnable定义线程主题类,用Thread启用线程

解释Thread与Runnable接口实现多线程的区别:
Thread 是Runnab 接口的子类
使用Runnable接口实现多线程可以避免但继承局限
Runnable 实现的多线程 比 Thread 实现的多线程更加清楚的描叙数据共享的概念

三:线程命名
所以的线程程序的执行,每一次都是不同的运行结果,因为它会根据自己的情况进行资源抢占,
所以如果区分每一个线程,就必须依靠线程的名字。对于线程一般在启动前进行定义。
如果想要进行线程名称的操作,可以使用Thread类的如下方法:
构造方法:public Thread (Runnable target,String name);
设置名字:public final void setName(String name)
取得名字:public final String getName()

对应线程名字的操作, 方法是属于Thread类的,如果换回到Runnable里面并没有继承Thread类,
如果要想取得线程名字,那么能够取得的就是当前执行方法的线程名字。所以在Thread类里面,提供了一个方法:
取得当前线程对象:public static Thread currentThread();
如果在实例化 Thread类对象时 没有为其设置名字 ,那么回自动的进行编号命名, 保证线程对象的名字不重复。


四:线程数目
主方法就是一个线程(main线程),所有在主方法上创建的线程, 都可以表示为子线程。
每当使用java命令去解释一个程序类的时候, 对于操作系统而言,都相当于启动了一个新的进程,而main只是新进程上的一个子线程。

问:每一个JVM启动的时候至少启动几个线程?
答:main 线程:
gc线程。

五:线程的休眠与优先级
所谓的线程休眠指的是让线程的程序稍微慢一点 ;
休眠的方法:
public static void sleep(long millis) throws InterruptedException

默认情况下,在休眠的时候如果设置了多个线程对象,那么所有的线程对象将一起进入到run()
方法(先后顺序太短);

优先级指的是越高的优先级,越有可能先执行。在Thread类里提供以下的两个方法,进行优先级操作;
设置优先级:public final void setPriority(int newPriority)
取得优先级:public final int getPriority()
设置和取得都有三种int数据类型的优先级:
MIN_PRIORITY
NORM_PRIORITY
MAX_PRIORITY

主线程的优先级 = 中等优先级;

总结:
Thread.currentThread() 取得当前线程对象;
Thread.sleep()主要是休眠 ,会感觉线程一起执行 , 实际有区别;
优先级越高的对象越有可能先执行

六:线程的同步
所谓的同步指的是同一线程访问同一资源时遇到的问题。
互联网上都属于异步应用,异步操作就会存在安全隐患
class myThread implements Runnable {
public int ticket = 5;
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 20; ++i) {
synchronized (this) {//指当前操作只允许一个对象进入
if (ticket > 0) {

try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "票数剩余 = " + this.ticket--);
}
}
}
}

}
public class thread {
public static void main(String[] args) {
myThread tm1 = new myThread();
new Thread(tm1, "票贩子A").start();
new Thread(tm1, "票贩子B").start();
new Thread(tm1, "票贩子C").start();
}
}
同步的操作:
1 . 如果有其他线程正在执行, 则其他线程停止访问该资源
在java里面,如果需要使用线程的同步 , 可以使用synchronized关键字,而这个关键字可 以通过两种方式使用;
一种是同步代码块;
一种是同步方法;
在java里面有四种代码块:
普通代码块,构造块,静态块,同步块;
同步操作与异步操作相比,异步的操作速度大于同步速度,但同步的安全性更高。
90%代码都是异步代码。


七:死锁
线程同步过多就有可能造成死锁。
死锁是程序开发之中由于某种逻辑上的错误所造成的问题,并且不是简单就会出现的。
面试题:请解释多个线程访问同一资源时要考虑哪些情况,有可能造成哪些问题?
多个线程访问同一资源时一定要处理好同步,可以使用同步代码或同步方法来解决,
但是过多的使用同步有可能造成死锁。
同步代码块 : synchronized(锁定对象)代码
同步方法: public synchronized 返回值 方法名称
/** 
* Java线程:并发协作-死锁 

* @author Administrator 2009-11-4 22:06:13 
*/
 
public class Test { 
        public static void main(String[] args) { 
                DeadlockRisk dead = new DeadlockRisk(); 
                MyThread t1 = new MyThread(dead, 1, 2); 
                MyThread t2 = new MyThread(dead, 3, 4); 
                MyThread t3 = new MyThread(dead, 5, 6); 
                MyThread t4 = new MyThread(dead, 7, 8); 

                t1.start(); 
                t2.start(); 
                t3.start(); 
                t4.start(); 
        } 



class MyThread extends Thread { 
        private DeadlockRisk dead; 
        private int a, b; 


        MyThread(DeadlockRisk dead, int a, int b) { 
                this.dead = dead; 
                this.a = a; 
                this.b = b; 
        } 

        @Override 
        public void run() { 
                dead.read(); 
                dead.write(a, b); 
        } 


class DeadlockRisk { 
        private static class Resource { 
                public int value; 
        } 

        private Resource resourceA = new Resource(); 
        private Resource resourceB = new Resource(); 

        public int read() { 
                synchronized (resourceA) { 
                        System.out.println("read():" + Thread.currentThread().getName() + "获取了resourceA的锁!"); 
                        synchronized (resourceB) { 
                                System.out.println("read():" + Thread.currentThread().getName() + "获取了resourceB的锁!"); 
                                return resourceB.value + resourceA.value; 
                        } 
                } 
        } 

        public void write(int a, int b) { 
                synchronized (resourceB) { 
                        System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceA的锁!"); 
                        synchronized (resourceA) { 
                                System.out.println("write():" + Thread.currentThread().getName() + "获取了resourceB的锁!"); 
                                resourceA.value = a; 
                                resourceB.value = b; 
                        } 
                } 
        } 
}
总结:最简单的理解同步或异步的操作,可以通过synchronized来实现;
死锁是一种不定的状态;


八:生产与销售模型
1.错位问题 , 用同步方法 解决
2.重复问题 , 加入等待与唤醒机制,在Object主类里提供有专门的处理方法
等待public final void wait() throws InterruptedException
唤醒第一个等待线程 public final void notify()
唤醒所有等待线程,优先级高先进行public final void notifyAll()

面试题:sleep() 与 wait() 的区别
sleep() 是 Thread() 定义的方法, 而 wait() 是Object 定义的方法
sleep ()可以设置休眠时间 , wait 可以使用notify() 进行唤醒


package com.intreface
import com.unite8.setDemo;
class Info {
public String content;
public String name;
private boolean flag = true;//销售与产生的状态
//true 表示可以生产,不可以取走
//false 表示可以取走,不可以生产
public synchronized void set(String content, String name) {
if (flag == false) {//已生产未销售
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// TODO Auto-generated method stub
this.name = name;
this.content = content;
this.flag = false;//应该产生新的
super.notify();//唤醒其他等待线程
}


public synchronized void get() {
if (flag == true) {//已销售未生产
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(this.name + "-" + this.content);
this.flag = true;//应该销售
super.notify();//唤醒其他等待线程
}


}


class product implements Runnable {
private Info info = new Info();


public product(Info info) {
this.info = info;
}


public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 100; ++i) {//随机生产两种产品
if (i % 2 == 0) {
this.info.set("A", "a");
} else {
this.info.set("B", "b");
}
}
}


}


class customer implements Runnable {
private Info info = new Info();


public customer(Info info) {
this.info = info;
}

@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 100; ++i) {//销售产品
this.info.get();
}
}


}


public class shop {
public static void main(String[] args) {
//因为用的是一个info,所以可以利用flag来实现等待和实现
Info info = new Info();//生成与销售工厂
customer cus = new customer(info);//销售
product pro = new product(info);//生产
new Thread(cus).start();//开始生产与销售
new Thread(pro).start();
}
}










0 0