ASP.Net+Android+IO开发S、.Net培训、期待与您交流!1、基础知识
进程:是指一个正在执行的程序,每一个进程执行,都有执行顺序,该顺序是一个执行路径,或者是一个控制单元
线程:就是进程中的一个独立的控制单元,线程控制着进程的执行,在线程执行中,至少有一线程执行
Vm 启动的时候有一个java.exe,该进程中至少有一个线程负责程序的执行,这个线程就是主线程
2.创建多线程
1》、我们可以利用java中的Thread类创建线程,Thread是程序中执行的线程。创建线程时,1》、必须继承Thread类; 2》、同时应该覆盖Thread类的run方法;3》、创建线程对象,即创建
所定义线程类的对象;4》开启线程,用对象的start方法(start的作用是:开启线程,并执行线程的run方法)
public class ThreadDemo1 extends Thread{
@Override
public void run() {
for(int i = 0; i< 60; i++)
{
System.out.println("thread run" +i);
}
}
}执行时调用对象的start方法
2》、线程的运行状态:五种状态,创建,运行,冻结,消亡,阻塞
3》、线程有名称,可以通过getName()的到线程名称,通过setName()来设置线程名称
自定义线程名称,我们通过调用父类的名称,亦可以通过;通过Thread.currentThread().getName()来获得当前线程的对象,currentThread是静态方法,获得那个线程是当前运行的对象
小实例:买票程序的实现:多个窗口实现同时买票,这样就有共享资源,所以在程序中我们应该用Thread来实现时,我们应该考虑票是临界资源
用Thread类实现时我们可以用静态变量来避免票被重复买
public class Ticket extends Thread //implements Runnable
{private static int ticket = 100;
public Ticket(String name)
{super(name);}
public void run() {
// TODO Auto-generated method stub
while(true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+" sale "+ticket--);
}}}}
4》、创建线程类的第二种方法:
步骤:1、定义实现Runnable接口的类
2、覆盖Runnable接口中的run方法(run方法中为线程要执行的程序代码)
3、通过Thread类来建立线程对象
4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
为啥要将Runnable接口的子类对象传递给Thread的构造函数
原因:自定义的run方法所属的对象是Runnable接口的子类对象
所以要让线程去指定对象的run方法。就必须明确该run方法所属对象
5、调用Thread类的start方法开启线程并调用Runnable接口的run方法
public class ThreadDemo2 implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i< 60; i++)
{
System.out.println(Thread.currentThread().getName()+"thread run" +i);
}
}
}
开启线程 Runnable r1 = new ThreadDemo2(); new Thread(r1).start();
5》、实现方式和继承方式有什么区别?
实现方式避免了单继承的局限性,在定义线程时一般使用实现方式;继承Thread类线程代码存放在thread的子类的run方法中,而实现的线程代码在接口的子类run方法中
3、多线程的安全性问题,出现的原因
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完成
另一个线程就获得了cpu的执行权,而执行其所要执行的语句,从而导致对共享数据的操作错误
解决方法:对多条共享数据的语句用同步方式处理,只能让一个线程在某一时间段内执行,执行完成后,再将cpu的使用权让出,这样在一个线程执行的过程中,其他线程不参与执行
1、java对于多线程的解决办法就是只用同步代码块的方式
synchronized(对象)
{
//需要同步的代码语句块
}
同步的代码块应该是那些操作共享数据的代码块
同步的原理:就是为资源的使用者上锁,当有线程使用共享资源是,对共享资源进行上锁,后来的线程等先来的线程将共享资源释放掉在使用共享资源,这样避免了CPU的使用权被后来
的线程占用
同步的前提是:1、必须要有两个或两个以上的线程共享同一资源;2、必须多个线程使用同一个锁,并且在同一段时间内只有一个线程在执行
线程的同步解决了多线程中存在的安全问题,但是它较为消耗资源
2、同步函数,带有synchronized修饰的函数为同步函数,同步函数也是用与解决多线程的安全性问题,同步函数使用的锁为this。只有两个锁相同时,对共享资源的访问才是安全的
public synchronized void add(int n)
{
sum += n;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("sum = "+sum);
}
3、使用静态同步函数时,所用的锁不是this啦,而是Class的对象这时锁就是所定义类的class对应的对象Class clazz = Ticket1.class;clazz为同步函数的锁
4、java多线程同步在单例模式中的应用
单例模式的两种格式:饿汉式代码 懒汉式代码如下:(延时加载问题)
class Single{ class Single{
private static final Single s = new Single(); private static Single s = null;
private Single(){} private Single(){}
public static Single getInstance() public static Single getInstance()
{return s;} { if(s == null) s = new Single(); return s;}
} }
由上面代码可知道,当懒汉式用在多线程程序中时,可能会出现问题:有多个线程要实例化Single对象时,A线程判断s为空,线程进入睡眠状态;B线程在判断s还为空,这是B线程创建
了一个Single对象,A再次运行时,不在判断s是否为空,就创建s对象,违背了单例设计模式,我们可以有两种解决问题方式
class Single
{
private static Single s = null;
private Single(){};
public synchronized static Single getInstance()//这样每个进程进来都先判断锁是否开启,比较消耗资源
{
if(s == null) s = new Single(); 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;}
}
}
}
5、多线程的死锁问题:出现的原因为同步中嵌套同步,而且两个锁不同引起的
6、线程间的通信
1》、等待唤醒机制,其实现主要靠wait()和notify()方法
其中wait方法让线程由运行状态变为冻结状态,冻结状态下,线程失去资源,没有执行的权利,只有当另外线程的唤醒(notify方法),才能从冻结状态转化为阻塞状态,
有执行所需要的资源,wait,notify(),notifyAll()都使用在同步中,因为要对持有监视器(同步锁)的线程做操作,所以要使用在同步中,因为只有同步才具有锁
synchronized(r)
{
if(!r.flag)
try{r.wait();}catch(Exception e){}//将线程至于冻结状态
System.out.println(r.name+"...."+r.sex);
r.flag = false;
r.notify();//拥有同样锁的线程可以唤醒拥有同样锁的等待进程,用notifyall可以唤醒拥有相同锁的其他等待进程
}
为什么这些操作的方法定义在Object类中?
因为这些方法在操作同步中线程时,都必须要有标志他们所操作线程只有的锁,因为只有被同一个锁上的线程才可以被同一个锁上的notify唤醒
即等待唤醒机制必须使用在同一个锁的同步代码块上,而锁可以是任意对象,因此wait和notify方法定义在Object中
2》、生产者消费者问题
在多个线程进行生产,多个进程进行消费的程序中我们应该用while进行判断,这样为了避免线程在为检测是否满足要求就去生产或者消费
while(flag)
try{this.wait();}catch(Exception e){}
this.name = name+"\t"+count++;
System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
this.notifyAll();//为了唤醒其他线程
在jdk1.5以后java中提供了新的解决方案。利用java.util.concurrent.locks包下提供的Lock接口和Condition接口,这两个接口相互配合,实现多线程之间资源共享的问题
Lock:替代了Synchronized
lock
unlock
newCondition()
Condition:替代了Object wait notify notifyAll
await();
signal();
signalAll();
实现的实例代码
private Lock lock = new ReentrantLock();
private Condition condition_produter = lock.newCondition();
private Condition condition_consumer = lock.newCondition();
public void set(String name)throws InterruptedException
{
lock.lock();
try
{
while(flag)
condition_produter.await();
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"\t生产者\t"+this.name);
flag = true;
condition_consumer.signal();
}
finally
{
lock.unlock();//释放锁的动作一定要执行。
}
}
7、停止线程
停止线程的原理:只有一种方法,即run方法的结束;开启多线程的运行,运行代码都是循环结构,所以我们只要控制住循环,就可以让run方法结束,也就是线程的结束
在特殊情况:当线程
8、守护线程:我么可以通过Thread类中的setDaemon()方法可以将线程设置为守护线程,这时线程为后台线程,当前台线程结束后,后台线程自动结束,注意:该方法在开启线程时调用
9、join是线程抢夺CPU的执行权,其他线程将等待该线程执行完成后,在回到阻塞状态
join的特点:当A线程执行到B线程的join方法时,A就会等待,等待B线程执行完,A才会执行,join可以用来临时加入线程执行
10、Priority和Yield
优先级,在java多线程中线程有优先级,优先级越高,其抢占到资源的概率越高
yield()
ASP.Net+Android+IO开发S、.Net培训、期待与您交流!
本文详细介绍了Java多线程的基本概念、创建方法、线程安全问题及解决方案、死锁问题、线程间通信机制等内容,并探讨了单例模式在多线程环境下的应用。
1386

被折叠的 条评论
为什么被折叠?



