JAVASE之多线程

多线程1

所谓的多线程就是有多个线程执行进程中的代码:
进程的概念:所谓的进程简单的理解就是正在进行的程序(应用程序),线程就是
执行进程中的代码的部分,一个进程中肯定会至少有一个线程,每一个线程都是有
对应的进程中的任务的。
多线程就是在一个进程中有多个线程来执行不同的功能代码的,其实在实际的
中任然不是多个同时执行的,是根据CPU的时间片来决定执行哪个进程的哪个线程的,
轮转到哪里就执行到哪里,但是由于轮转的速度是很快的,所以感觉到是同时执行的
一样。多核的是同时执行的。
在实际的开发中main函数中就是一个多线程的例子,当在实际的main函数中发生了
垃圾的时候,就会起用新线程调用垃圾回收机制,垃圾回收机制就是通过垃圾回收器
来执行的,垃圾回收器是通过system类的gc()方法来实现的。
object 类中有一个finalize()方法,这个方法再回收垃圾的时候调用。任何类都可以
重写这个方法

多线程的实现方式:
其一就是继承Thread,然后重写这个类的run方法,这里的run方法就是要单独线程
来执行的代码,然后创建一个对象,调用start()方法【内部的实现是开启线程然后由】
虚拟机调用该对象的run方法】注意这里如果直接的通过对象来调用run方法的话就是单线程
来执行的,要使用多线程的时候就要调用线程类的start方法,才能多线程。

多线程2

线程的几种状态:
线程有创建,运行,冻结,和结束四种状态,创建一个线程就是通过继承能一个Thread类,然后new对象就
创建了一个线程,运行的话就是通过创建的实例去调用Thread父类中的start()方法,来使线程运行,冻结就是
当一个线程对象调用了sleep(time)方法之后就会冻结,这时候CPU就不会去轮转执行这个线程的任务,直到
time时间后,该线程再次的恢复到了运行的状态,使线程到冻结的状态还有wait()方法,这个方法是没有参数的
如果不调用notity()方法的话就会一直的冻结下去,当一个线程执行完了该线程对相应的run()方法之后,该线程
就处于结束的状态了。
多线程的两种实现的方式,如果是直接的继承Thread类的话,就直接的可以通过对象来调用start()方法了执行
当前线程的任务
eg:class ThreadDemo extends Thread{
public void run(){
Sysout.out.println("helloworld!!!");
}
}
class Demo {
public static void main(String []args){
ThreadDemo d = new ThreadDemo();
ThreadDemo d1 = new ThreadDemo();
d.start();
d1.start();
}
}
上面的代码的执行的时候将会开启三个线程,其中两个线程d和d1是手动开启的,另一个是主线程。
当如果使用实现Runnable接口的时候就不能直接的这么使用对象的,而要使用Thread对象来创建线程
然后通过Thread构造函数来实现多线程的操作。
eg:class ThreadDemo inplements Runnable{
public void run(){
Sysout.out.println("helloworld!!!");
}
}
class Demo {
public static void main(String []args){
Runnable r = new ThreadDemo();
Thread d = new Thread(r);
Thread d1 = new Thread(r);
d.start();
d1.start();
}
}
上面的代码就是通过两个线程来执行了
多线程出现的问题:
当多线程共享资源的时候就会出现问题,在这里首先要明确一点继承Thread类和实现Runnable借口的不同
class ThreadDe extends Thread{
private int num = 100;
public void run(){
while(true){
if(num>0){
Sysout.out.println(Thread.currentThread.getName()+ num--);
}
}
}
}
class ThreadDemo {
public static void main(String[]args){
ThreadDe t1 = new ThreadDe();
ThreadDe t2 = new ThreadDe();
t1.start();
t2.start();
/**
ThreadDe t1 = new ThreadDe();
t1.start();
t1.start();
这种写法会抛出异常的,但是不影响程序的运行,会抛出不正确的线程状态异常的。
*/
}
}
上面的例子就会出现答应了200次,这时为什么呢,因为这里的变量是对象变量,每一个对象都有一个
num值得,当创建了两个对象的时候就会有两个这样的值,所以会答应200次,如何解决的这个办法,一种
就是让这个类中所有的对象都去共用这个变量,即将其弄成静态的变量。还有一种方式就是不要去继承
Thread类,而去实现Runnable接口。然后给每个线程任务去执行。
class ThreadDe implements Runnable{
private int num = 100;
public void run(){
while(true){
if(num>0){
try{
Thread.sleep(10);//在实现了Runnable接口的类中不能将sleep()方法的异常抛出去,只能处理@1------------------@1
Sysout.out.println(Thread.currentThread.getName()+ num--);@2----------------------------------------------@2
}
catch(illienThreadStatusException e){
e.getMessage();
}
}
}
}
}
class ThreadDemo {
public static void main(String[]args){
ThreadDe t = new ThreadDe();
Thread t1 = new Thread(t);
Thread t2 = nw Thread(t);
t1.start();
t2.start();
}
}
如上的写法因为是一个对象的,所以就不会出现上面的问题的,但是这种共享的数据的时候,而且共享
数据的代码超过两行的时候(多线程执行这里的if语句块)就会出现多想的问题。
当t1线程指向到@1时候CPU轮转到t2线程执行,这样就会导致结果的出错,解决这个问题的办法就是
引入同步代码块synchronized(对象){}
上面的代码修改如下
class ThreadDe implements Runnable{
private int num = 100;
Object obj = new Object();//当把这个对象放在run方法里面的时候这里的同步块就没有了作用,因为每一个线程都有一个锁了,同步是没有用的,同步的前提就是多线程,共用同一个锁
public void run(){
while(true){
synchronized(obj){
if(num>0){
try{
Thread.sleep(10);//在实现了Runnable接口的类中不能将sleep()方法的异常抛出去,只能处理@1------------------@1
Sysout.out.println(Thread.currentThread.getName()+ num--);@2----------------------------------------------@2
}
catch(illienThreadStatusException e){
e.getMessage();
}
}
}

}
}
}
这里就不会出现多线程的问题了,synchronized代码块的修饰是将if和Sysout两句同时的让一个线程来执行的。执行完了才允许另外的线程去执行
非静态的同步函数的锁是this对象,静态的函数的锁是该类的类文件(.class)文件。
单利模式在多线程的使用:
单利模式有两种形式,分别为懒汉式和饿汉式,所谓的懒汉式就是在调用的时候才初始化对象,饿汉事是在加载的时候就初始化
饿汉式:
class Single{
privte static final single = new Single();
private(){}
public static Single getInstance(){
return single;
}
}
这里的饿汉式不存在多线程的问题。
懒汉式:
class Single{
private static single = null;
private Single(){}
public static Single getInstance(){
if(single=null){
single = new Single();
}
return single;
}
}
这里就会存在多线程的问题,解决的问题就是讲这个函数变为同步函数即:public static synchronized Single getInstance(){},
但是这种做法会影响效率,要解决这个效率问题,就讲同步函数变为同步的代码块:
 class Single{
private static single == null;
private Single(){}
public static Single getInstance(){
synchronized(Single.class)//这里使用的是静态的方法,所以锁对象是该类的class文件。
{
if(single==null){
single = new Single();
}
}
return single;
}
}
上述的解决方法一样的存在效率的问题,于是只有在single为null的时候在进同步块,最终代码如下:
 class Single{
private static single = null;
private Single(){}
public static Single getInstance(){
if(single == null){
synchronized(Single.class)//这里使用的是静态的方法,所以锁对象是该类的class文件。
{
if(single==null){
single = new Single();
}
}
}
return single;
}
}
死锁的概念:
所谓的死锁就是在两个同步块中分别的持有对方的锁的对象,就会造成死锁,出现多线程的问题就是
多个线程有共享的数据,而且操作共享数据的代码多余两行

多线程3

多线程中的wait()方法和notify(),notifyAll()方法:
首先的要清楚这几个方法是在Object类中定义的方法,当使用这几个方法的时候,一定要在同步
代码块中去使用,因为这里的wait()和notify()方法相对于锁来说的,当一个锁使用了wait()方法之后
这个线程就位于这个对象的线程池中,当使用了wait方法之后只有等待具有相同锁的线程调用notify来
是这个线程处于可执行的状态
wait()和sleep()方法的区别:
wait()和sleep()方法都会失去CPU的执行权,但是wait()会释放锁,sleep()方法是不会释放锁的
注意:在同步代码块中可能会有多个具有执行权的线程,但是只有一个会执行的,因为只有一个会得到锁
的。
让线程结束的方法:
stop()方法已经不建议使用了,当一个线程的run()方法执行完之后这个线程就会结束,也可以使用
intterupt()方法来唤醒睡眠或者wait()中的线程,这种事强制的,会抛异常的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值