关于java多线程简单介绍.1


用到的包和类名以及常用的方法

java.long包和thread类 回收验证是覆盖object里面的finalize()和system.gc()的结合运用

run() start() Thread.currentThread().getname()//获得进程的名字 Thread.sleep(毫秒)延迟的函数

============================================

创建多线程的方法

方法一******************************
1.创建一个类继承Thread 2 .覆盖父类里面的run方法里面存储的是线程的执行代码
3创建一个对象就是创建一个线程对象,4.用对象.start来开始多线程,多线程里面运行的是
你的类覆盖的run里面的执行代码,
方法二**********************************
1.链接一个接口这个接口是为非Thread 子类提供的一种激活方式
通过实例化某个 Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。
2.new一个有Rannable 接口的实例例如是t,在用Thread t1=new Thread (t);然后里面t1.start();开始进程
@1定义一个类实现Runnable这个接口
@2覆盖Runnable里面的run方法,存储的是执行代码,
@3thread类创建线程对象,并将实现了的Runnable接口的对象作为Thread类里面构造函数的参数来使用
@4 运行start()的方法,开启多线程并且执行任务代码;


上面两种多线程的方法:我们一般使用第二种,好处
1.避免了继承Thread类单继承的局限性
2.更加符合面向对象的思想,把进程进行了单独的封装,
3.Runnalble的出现降低了线程跟线程对象之间的耦合性

关于进程

进程就是指应用程序在内存中分配的空间,只此一个的的进程是没有意义的所以会有一个线程来在进程中负责程序的执行单元;cpu中的晶体存储着指令集来负责程序的运算,,同一时间只能执行一个指令,但是它也能在不同的指令之间不停的切换,因为速度很快所以呢,人感觉不出来,所以会感觉可以同时执行很多的指令,但是多了也不行,会出现卡顿,(一个内核可以单独的执行所以,内核多了运行会很快),多线程有一个随机性就是因为cpu这种的处理方式;
所以多线程技术归根就是多个代码块同时的运行,但是不代表他即是高效,,只能说他能合理的利用cpu的资源;
堆中也会用到多线程,因为堆在开辟空间的时候,会一边开辟一边回收;用的方法就是object类中的finalize的方法,,因为是object类所以可以直接的覆盖和调用(System.gc()//启动垃圾回收),方法如下

实例-

public class lajihuishou
{
public void finalize()
{
System.out.println("回收成功"); 
}
}
public class Test
{
public static void main(String [] args){
    new lajihuishou();
    new lajihuishou();
    new lajihuishou();
    new lajihuishou();
    new lajihuishou();
    new lajihuishou();new lajihuishou();
    System.gc();//启动垃圾回收装置与自己覆盖的finalize方法一起工做
    System.out.println("++++++++++++++++++++++++");
}
}

注意gc()方法用的位置,如果放在开头,还没有启动就已经执行完了;真正回收操作的是finalize这个方法;每运行结果不一样,是因为随机性,main的线程就是主线程

package xiancheng;

public class threadTest extends Thread
{ private String name ;
public  threadTest(String name){
    this.name =name ;
}

1.继承thread这个类2.覆盖run方法,run方法里面是多线程执行的任务代码
3.创建一个对象就是就是创建一个线程对象;4.对象.start开始线程,执行run方法里面的代码

public void run(){
    show();
}
public void show(){
    for(int i=0;i<10;i++){
    System.out.println(name+"+++"+i);

    }
}
}

下面是执行代码

public class Test1
{
public static void main(String[] args){
    threadTest thre1=new threadTest("哈哈");
    threadTest thre2=new threadTest("呵呵");
    thre1.start();//不运行的话就不能启动多线程,是运行覆盖      run里面的任务代码
    thre2.start();

}
}

================================================================
售票的实例:
代码一:运用第一种方法构建thread子类的方式实现多线程,但是不符合实际

package xiancheng;

import javax.swing.event.TreeWillExpandListener;
//此方法的会同时创建400张票,所以不符合实际,而且尽量不要用到static,所以会用第二种的创建
//线程的方法及runnable的类,此方法可以共享所用到的资源
public class TicketTest extends Thread
{
    private int ticket=100;
    public void run(){
        while(true){
        if(ticket>0){
        System.out.println(Thread.currentThread().getName()+"===" +  ticket--);
        }//调用Thread.cuurrentThread获得当前执行的进程.getname是获取当前进程的名字
        }
        }
public static void main(String [] args){
    TicketTest test1=new TicketTest();
    TicketTest test2=new TicketTest();
    TicketTest test3=new TicketTest();
    TicketTest test4=new TicketTest();
    test2.start();
    test1.start();
    test3.start();
    test4.start();
}

}

第二种方法呢,运用调用接口的方法,此方法符合实际也就造成了内部票的出现

package xiancheng;

public class TicketTest2 implements Runnable
{
private int ticket=100;

public void run()
{
    // TODO Auto-generated method stub
    while(true){
        if(ticket >0){
            System.out.println(Thread.currentThread().getName()+"+++"+ticket--);
        }
    }

}
public static void main(String[] args){
    TicketTest2 t=new TicketTest2();
    Thread t1=new Thread(t);//这里的t一定是定义的runnable接口的类
    Thread t2=new Thread(t);//不理解去找apiRunnable 为非 Thread 
    //子类的类提供了一种激活方式。通过实例化某个 Thread 实例并将自身作为运行目标,
    //就可以运行实现 Runnable 的类而无需创建 Thread 的子类。
    //大多数情况下,如果只想重写 run() 方法,而不重写其他 Thread 方法,
    //那么应使用 Runnable 接口。这很重要,
    //因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。 

    Thread t3=new Thread(t);
    Thread t4=new Thread(t);
    t1.start();
    t3.start();
    t2.start();
    t4.start();

}
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
但是如果把run里面的执行代码改成

while(true){
        if(ticket >0){
            try
            {
                Thread.sleep(10);
            }
            catch (InterruptedException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"+++"+ticket--);
        }
    }
//Thread.sleep(毫秒数),

那么多线程就会出现延迟,以至于出现,程序已经执行完毕,但是有的线程处于临时阻塞的状态
有执行资格,但是没有执行权,还处于运行,所以依然是执行ticket–;
所以会出现ticket的票号是0,或者负数的情况;造成的最终原因是当一个进程执行到if(ticket>0)后
出现时间阻塞的现象,cup的随机切换处理;

总结原因是
1.进程里面有共享的数据
2.有多条对共享数据的操作,一个线程在操作共享数据
的过程中,其他的线程参与了运算,造成了数据的错误
解决的办法:用同步的代码块
synchronized(对象)
{
被同步的代码
}
这个synchonized并不是都要把放在自己覆盖的run()里面的执行代码,覆盖进去,根据自己的实际的需求,多测试几遍,安全就好,上面的代码仅供参考,运行代码的时候,多运行几遍,你会发现很多的不同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值