Java基础(包、多线程)


一、包

作用:

1、用于给类文件进行分类管理

2、给类提供多层命名空间

特点:

1、必须写在程序中的第一行

2、类的全称是包名.类名

3、其实也是一种封装形式

声明包:格式    package    包名

自动生成包: 格式:   javac  -d   空格 . 空格  要编译的Java文件

注:

1、-d是为了指定包存放的位置,-d后面可以跟路径  “空格 . 空格”代表的是在cd所跳到的目录下存放

2、声明包后,如果要运行Java字节码文件(.class)文件,则必须要使用包名.类名进行访问  如:声明的包为page ,类为Test,那么你在dos命令行要运行Test,则必须通过 Java page.Test来访问

包的好处:可以让程序中的类文件与源文件分离

不同包中的类如何访问:

1、A包想要使用B包中的类,必须对B包中的类进行标识  也就是说在创建B包中的类时,需要带上包名

2、当A包与B包不在同一目录下时,,需要告诉jvm去哪里找指定的包  需要配置classpath

3、包与包之间进行访问,如果不存在关系(继承、接口),那么被访问的包中的类以及类中的成员必须被public修饰

4、如果包与包之间之间存在关系,那么可以直接访问被public和protected修饰符修饰的成员

四中权限:

publicprotected默认private
同一个类中 OK OK OK OK
同一个包中 OK OK OK NO
不同包中子类 OK OK NO NO
不同包中 OK NO NO NO

权限修饰符大小:public > protected > 默认 > private

导入包:通过inport关键字实现   import  包名

包名定义规范:

1、可以使用URL来完成,因为URL是唯一的          格式为:  如  www.baidu.com              写成包名就是:com.baidu.类名

2、包名当有多个单词组成时,所有字母均小写

Jar包:DOS命令行中输入jar可以查看具体参数

把多个包压缩成jar包:格式   jar -cf  生成的jar包名  要压缩的文件夹(包名)

查看jar包中的文件信息:格式: jar -tf 要查看的架文件名

把jar包中的信息导入到文件中(数据重定向): 格式: jar -tf  要导出的Jar文件 > 要导入的路径

注意:

1、有一个小细节特别致命  在jdk所在的路径下的lib文件夹下有一个可执行文件  tools.jar  他是用来保证javac正常执行的,不可以更换路径会该名称

2、Jdk所在目录下有一个压缩文件  src.zip  他是Java的所有类的源文件,可以修改

二、多线程

一、什么是多线程?

要想了解线程就必须要先了解进程,什么是进程呢?大家都玩过任务管理器吧?嗯哼,是不是懂了一点??

1、进程:其实进程就是一个正在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径(或者叫一个控制单元)

2、线程:其实就是进程中的一个独立的控制单元,线程在控制着进程的执行

注:一个进程中至少有一个线程

3、多线程

       java虚拟机启动的时候会有一个java.exe的执行程序,也就是一个进程。该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。JVM启动除了执行一个主线程,还有负责垃圾回收机制的线程。像种在一个进程中有多个线程执行的方式,就叫做多线程。

4、多线程存在的意义

        多线程的出现能让程序产生同时运行效果。可以提高程序执行效率。

        例如:在java.exe进程执行主线程时,如果程序代码特别多,在堆内存中产生了很多对象,而同时对象调用完后,就成了垃圾。如果垃圾过多就有可能是堆内存出现内存不足的现象,只是如果只有一个线程工作的话,程序的执行将会很低效。而如果有另一个线程帮助处理的话,如垃圾回收机制线程来帮助回收垃圾的话,程序的运行将变得更有效率。

5、计算机CPU的运行原理

        我们电脑上有很多的程序在同时进行,就好像cpu在同时处理这所以程序一样。但是,在一个时刻,单核的cpu只能运行一个程序。而我们看到的同时运行效果,只是cpu在多个进程间做着快速切换动作。

        cpu执行哪个程序,是毫无规律性的。这也是多线程的一个特性:随机性。哪个线程被cpu执行,或者说抢到了cpu的执行权,哪个线程就执行。而cpu不会只执行一个,当执行一个一会后,又会去执行另一个,或者说另一个抢走了cpu的执行权。至于究竟是怎么样执行的,只能由cpu决定。

二、创建线程

创建线程有两种方式:继承方式和实现方式

一、继承方式

通过对API的查找,我们发现Java中已经提供对线程这类食物的描述,就是Thread类,因此我们只需要继承Thread类就可以了

1、步骤:

1、定义类继承Thread类

2、重写Thread类中的run方法

复写run方法仅仅是为了将自定义的代码存储(封装)在run方法中,并不会开启线程,还是一个线程,如果仅仅是调用run方法,那么调用一般函数没什么区别

3、创建子类对象,相当于创建一个线程

4、调用线程中的start方法(用于开启线程)

该方法有两个作用:1、启动线程    2、调用run方法

注:如果直接使用对象调用run方法,仅仅代表的是创建了线程,并没有运行,而要运行线程,必须调用start方法

2、为什么一定要复写run方法?

原因:Thread用于描述线程,该类就定义了一个功能用于存储线程需要运行的代码,该存储功能就是fun方法,也就是说Thread类中的run方法就是用来存储线程要运行的代码的。

3、代码实现:

class Demo extends Thread
{
//覆盖父类中的run方法
 public void run(){
for(int x=0;x<30;x++){
System.out.println("Demo......."+x);
}
}
}

class ThreadDemo1
{
public static void main(String[] args)
{
Demo d = new Demo();//创建一个线程
d.start();//开启线程并调用run方法

//主线程
for(int i=0;i<30;i++){
System.out.println("main....."+i);
}
}
}</span>

4、多线程小练习

/*
需求:创建两个线程,和主线程交替运行。并打印线程名称

如何打印线程名称呢?
我们可以通过父类中提供的方法进行获取 getName()或Thread。currentThread().getName()
注意:currentThread是静态的,所以可以直接使用类名.调用 是返回对当前正在执行的线程对象的引用。 调用时相当于this


//通过运行发现,线程名称打印出来了 格式是:Thread-编号 编号从0开始
那么我们怎么自定义线程名称呢?
通过查看API我们发现Thread类中已经定义了Thread(String name)构造函数 所以可以通过子类构造函数向父类传参
*/
class Demo extends Thread
{
//初始化线程名
Demo(String name){
super(name);
}
public void run(){
System.out.println("Thread.currentThread()==this="+Thread.currentThread()==this);//结果为true
for(int x=0;x<60;x++){
System.out.println(this.getName()+".....run...."+x);
}
}
}


class ThreadDemo2
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
Demo d1 = new Demo("One");
Demo d2 = new Demo("Two");
d1.start();
d2.start();


//主线程
for(int i=0;i<40;i++){
System.out.println(Thread.currentThread().getName()+"......run"+i);
}
}
}


二、实现方式

1、步骤:

1、定义类实现Runnable接口

2、复写Runnable中的run方法

3、通过Runnable接口的子类创建对象

4、把Runnable接口的子类对象作为实际参数传递给Thread类的构造函数

5、调用Thread类的start方法,开启线程,并调用Runnable接口的run方法

注:为什么一定要将Runnable接口的之类对象作为实际参数传递给Thread类的构造函数?

原因:因为自定义的run方法所属的对象时Runnable接口的子类对象,而该对象中是没有开启线程的方法的,所以要让线程执行指定对象的run方法就必须明确run方法所属的对象,然后调用start方法开启线程

2、实现方式的好处:避免了单继承出现的局限性,在定义线程是建议使用实现方式

注:为什么建议使用实现方式?

原因:因为使用继承创建线程会有一个弊端,那就是要继承Thread类,如果自定义类已经继承了其他类,那么在使用继承方式时,由于该类已经继承了其他类,而Java并不支持多继承,所以就不能再继承Thread类了,出现了局限性。而实现方式却不会发生这种情况,因为他可以在继承其他类的同时在实现Runnable接口

3、示例程序:

/*
需求:用多线程实现多个窗口卖票
*/
//使用继承方式
class ExtendsThread extends Thread
{
private int tick = 100;//继承方式 共享数据会出现不正常情况
public void run(){
while(true){//控制程序一直循环,知道票卖完
if(tick>0)
System.out.println(Thread.currentThread().getName()+".....run...."+tick--);
}
}
}

//使用实现方式
class ImplementThread implements Runnable
{
private int tick = 100;
public void run(){
while(true){//控制程序一直循环,知道票卖完
if(tick>0)
System.out.println(Thread.currentThread().getName()+".....run...."+tick--);
}
}
}
class ThreadDemo3
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
//使用继承方式创建线程
/*
ExtendsThread et1 = new ExtendsThread();//创建一个线程
ExtendsThread et2 = new ExtendsThread();
ExtendsThread et3 = new ExtendsThread();
ExtendsThread et4 = new ExtendsThread();
et1.start(); //开启线程
et2.start();
et3.start();
et4.start();
*/
/*通过运行发现,使用继承出现了不正常数据,所以使用继承创建多线程时,如果有使用到共享数据时,共享数据必须被static修饰,不然就会出现不正常数据 而实现会么???*/


//使用实现方式创建线程
ImplementThread it = new ImplementThread();//创建Runable接口子类对象
Thread t1 = new Thread(it); //创建线程
Thread t2 = new Thread(it);
Thread t3 = new Thread(it);
Thread t4 = new Thread(it);
t1.start(); //开启线程
t2.start();
t3.start();
t4.start();

/*运行后发现并没有出现继承方式中出现的问题,因为使用实现方式操作的是同一个对象的tick,数据共享了*/

}
}
实现方式运行结果:


继承方式运行结果:


注:通过继承方式运行结果发现不同线程中出现了重复值得情况,说明线程操作的不是同一个对象

4、实现方式和继承方式的区别:

继承Thread:线程代码存放在Thread子类run方法中。

实现Runnable:线程代码存放在接口子类run方法中。

继承操作的不是同一个Thread类的子类对象,而实现操作的是同一个Runnable接口的子类对象

三、线程中的几种状态

        被创建:等待启动,调用start启动。

        运行状态:具有执行资格和执行权。

        临时状态(阻塞):有执行资格,但是没有执行权。

        冻结状态:遇到sleeptime)方法和wait()方法时,失去执行资格和执行权,sleep方法时间到或者调用notify()方法时,获得执行资格,变为临时状态。

        消忙状态:stop()方法,或者run方法结束。

注:当已经从创建状态到了运行状态,再次调用start()方法时,就失去意义了,java运行时会提示线程状态异常。

图解:

注:这里的wait()方法和sleet()方法是有区别的:wait()会释放cpu执行权,释放锁。而sleep虽然也会释放执行权,但是却不会释放锁

四、线程安全问题

导致问题出现的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句还没有执行完,另一个线程得到了执行权,参与运行了,导致共享数据错误

解决办法:

对多条操作共享数据的语句,在某个时间段,让一个线程把有共享数据参与的语句一次性执行完,在该线程执行过程中,其他进程不可以参与执行

解决体现形式:同步代码块和同步函数

同步原理:对象就如同锁,持有锁的线程可以在同步中执行,没有持有所得线程即使获取了cpu的执行权,也进不去,因为没有获取锁,也就是没有钥匙,比较经典的例子:火车上的卫生间

1、同步代码块

用法: synchronized(对象)

{

需要同步的代码;

}

示例:

/*
需求:给买票程序加上同步代码块
*/
class ImplementThread implements Runnable
{
private int tick = 100;
Object obj = new Object();
public void run(){
while(true){//控制程序一直循环,知道票卖完
//同步,也就是上锁
synchronized(obj){
if(tick>0){
try
{
//使用线程中的sleep方法,模拟线程可能出现的问题
//因为sleep方法有抛出异常,而run方法不能抛出异常,所以应在内部try处理
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+".....run...."+tick--);
}
}
}
}
}
class ThreadDemo4
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
ImplementThread it = new ImplementThread();//创建Runable接口子类对象
Thread t1 = new Thread(it);
Thread t2 = new Thread(it);
Thread t3 = new Thread(it);
Thread t4 = new Thread(it);
t1.start();//开启线程
t2.start();
t3.start();
t4.start();
}
}
未同步运行结果:

同步后结果:


2、同步函数

        格式:在函数加上同步即可:public synchronized void show(){}

        那么同步函数用的是哪一个锁呢?

        函数需要被对象调用。那么函数都有一个所属对象引用。就是this。所以同步函数使用的锁是this

示例:

/*
需求:给买票程序加上同步代码块
*/
class ImplementThread implements Runnable
{
private int tick = 100;
Object obj = new Object();
public void run(){
while(true){//控制程序一直循环,知道票卖完
show();
}
}
private synchronized void show(){
if(tick>0){
try
{
//使用线程中的sleep方法,模拟线程可能出现的问题
//因为sleep方法有抛出异常,而run方法不能抛出异常,所以应在内部try处理
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+".....run...."+tick--);
}
}
}
class ThreadDemo5
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
ImplementThread it = new ImplementThread();//创建Runable接口子类对象
Thread t1 = new Thread(it);
Thread t2 = new Thread(it);
Thread t3 = new Thread(it);
Thread t4 = new Thread(it);
t1.start();//开启线程
t2.start();
t3.start();
t4.start();
}
}

3、同步的前提

1、必须要有两个或两个以上的线程

2、必须是多个线程使用同一个锁

4、同步利弊

1、解决了多线程的安全问题

2、多线程都需要判断锁,较为消耗资源,降低了程序效率

5、如何找线程中的问题

1、明确哪些代码是多线程要运行的代码

2、明确共享数据

3、明确多线程运行代码中那些语句是操作共享数据的

6、静态同步函数

静态同步函数使用的锁匙什么呢?

原理:通过验证发现不在是this,因为静态方法中不可以定义this,静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码对象,类名.class该对象的类型是class,所以静态同步函数使用的锁匙该方法所在类的字节码 文件对象,也就是类名.class,并且该对象在内存中是唯一的,因为字节码文件是唯一的

示例:

/*静态同步函数*/

class ImplementThread implements Runnable
{
private static int tick = 100;
Object obj = new Object();
public void run(){
while(true){//控制程序一直循环,知道票卖完
//show();
//静态同步代码块
/**/
//synchronized使用的锁是所在类的字节码文件 类名.class
synchronized(ImplementThread.class){
if(tick>0){
try
{
//使用线程中的sleep方法,模拟线程可能出现的问题
//因为sleep方法有抛出异常,而run方法不能抛出异常,所以应在内部try处理
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+".....run...."+tick--);
}
}

}
}
//静态同步函数
private static synchronized void show(){
if(tick>0){
try
{
//使用线程中的sleep方法,模拟线程可能出现的问题
//因为sleep方法有抛出异常,而run方法不能抛出异常,所以应在内部try处理
Thread.sleep(10);
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread().getName()+".....run...."+tick--);
}
}
}
class ThreadDemo7
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
ImplementThread it = new ImplementThread();//创建Runable接口子类对象
Thread t1 = new Thread(it);
Thread t2 = new Thread(it);
Thread t3 = new Thread(it);
Thread t4 = new Thread(it);
t1.start();//开启线程
t2.start();
t3.start();
t4.start();
}
}

五、死锁

可能出现死锁的情况:通常都是同步中嵌套同步而锁却不同时

写一个死锁程序:

/*
需求:写一个死锁程序
原理:同步里面嵌套同步,
*/
//自定义两个锁
class Demo
{
public static Object demoA = new Object(); //创建A锁
public static Object demoB = new Object(); //创建B锁
}
class DemoTest implements Runnable
{
int x = 0;
private boolean falg = true;
DemoTest(boolean falg){
this.falg = falg;
}
public void run(){
if(falg){
while(true){
synchronized(Demo.demoA){ //使用A锁
System.out.println(Thread.currentThread().getName()+"......demoA....");
synchronized(Demo.demoB){ //使用B锁
System.out.println(Thread.currentThread().getName()+"......demoB....");
}
}
}

}
else{
while(true){
synchronized(Demo.demoB){ //使用B锁
System.out.println(Thread.currentThread().getName()+"......demoB....");
synchronized(Demo.demoA){ //使用A锁
System.out.println(Thread.currentThread().getName()+"......demoA....");
}
}
}
}
}
}
class ThreadDemo8
{
public static void main(String [] agrs){
new Thread(new DemoTest(true)).start(); //启动线程
new Thread(new DemoTest(false)).start();
}
}

结果:程序被卡住,不能执行


六、线程间通讯

定义:其实就是多个线程在操作同一个资源,但是操作的动作不同

示例图:



代码体现一:

/*需求:使用多线程实现线程间通信,要求一个线程往资源中添加,另一个线程往外输出添加的内容
思路:1、要使用线程通信,必须要有资源类
2、根据需求:需要两个线程同时操作一个资源,而要实现同步,必须保证这两个线程都在操作同一把锁
*/

//定义资源类
class Res
{
//定义成员变量用于作为共享数据被线程进行添加和输出
private String name;
private String sex;
//用于让线程等待
private boolean flag = false;
//定义输入线程要操作的代码,由于数据是成对(name,set)添加的,所以应同步
public synchronized void setInput(String name, String sex){
if(flag)
try{
System.out.println(Thread.currentThread().getName()+"+....................................................11111wait");
wait();
}
catch(Exception e){

}
//这里只能使用if语句,不可以使用if else语句,因为无论flag是否为true,下面代码都是要执行的,flag只是用来防止覆盖用的
this.name = name;
this.sex = sex;
flag = true;
System.out.println("..........................................1111执行了..."+flag+"..."+name+"...."+sex);
notify();
}
//定义输出线程要操作的代码,因为要使用同步,所以必须保证至少有两把锁,所以该函数也需要同步
public synchronized void getOutput(){
if(!flag)
try{
System.out.println(Thread.currentThread().getName()+"+....................................................2222wait");
wait();
}
catch(Exception e){

}
System.out.println(Thread.currentThread().getName()+"..."+name+"...."+sex);
flag = false;
System.out.println("..........................................2222执行了...flat="+flag);
notify();
}

}
//定义输入线程
class Input implements Runnable
{
private Res r;
Input(Res r){
this.r = r;
}
public void run(){
int x = 0;
while(true){
if(x%2==0)
r.setInput("MK","Man");
else
r.setInput("张三","男男男男");
//System.out.println("........................................x="+x);
x++;
}
}
}
//定义输出(打印)线程
class Output implements Runnable
{
private Res r;
Output(Res r){
this.r = r;
}
public void run(){
while(true){
r.getOutput();
}
}
}

class ThreadDemo9
{
public static void main(String[] args)
{
Res r = new Res();//把对象作为实际参数传递,保证线程操作的资源是同一个
new Thread(new Input(r)).start();//启动线程
new Thread(new Output(r)).start();
}
}

练习2

/*
需求:要求使用线程通信完成多个输入线程和多个输出线程同时操作资源
思路:和刚刚我们做的差不多,稍微改下代码就行
*/
//定义资源类
class Res
{
//定义成员变量用于作为共享数据被线程进行添加和输出
private String name;
private String sex;
//用于让线程等待
private boolean flag = false;
//定义输入线程要操作的代码,由于数据是成对(name,set)添加的,所以应同步
public synchronized void setInput(String name, String sex){
//这里需要改变,因为是多个线程在操作同一段代码,唤醒后都需要判断
while(flag)
try{
System.out.println("............................................."+Thread.currentThread().getName()+"wait++++++++"+flag);
wait();//t1(放弃)(获取) t2(放弃)(获取)
}
catch(Exception e){

}
//这里只能使用if语句,不可以使用if else语句,因为无论flag是否为true,下面代码都是要执行的,flag只是用来防止覆盖用的
this.name = name;
this.sex = sex;
System.out.println(Thread.currentThread().getName()+"...."+name+"...."+sex+".........................新添");
flag = true;
notifyAll();//唤醒线程池中的所有线程,防止线程全部等待
}
//定义输出线程要操作的代码,因为要使用同步,所以必须保证至少有两把锁,所以该函数也需要同步
public synchronized void getOutput(){
while(!flag)
try{
System.out.println("................................................."+Thread.currentThread().getName()+"wait——————"+flag);
wait();//t3(放弃)(获取) t4(放弃)(获取)
}
catch(Exception e){

}
System.out.println(Thread.currentThread().getName()+"........."+name+"...."+sex+"++++++++++++++++打印");
flag = false;
notifyAll();
}

}
//定义输入线程
class Input implements Runnable
{
private int x;
private Res r;
Input(Res r){
this.r = r;
}
public void run(){
while(true){
if(x%2==0)
r.setInput("MK","Man");
else
r.setInput("张三","男男男男");
x++;
}
}
}
//定义输出(打印)线程
class Output implements Runnable
{
private Res r;
Output(Res r){
this.r = r;
}
public void run(){
while(true){
r.getOutput();
}
}
}
class ThreadDemo10
{
public static void main(String [] args){
Res r = new Res();
//创建输入对象,并作为实际参数传递,保证线程使用的是同一个对象
Input in = new Input(r);
Output out = new Output(r);
new Thread(in).start();
new Thread(in).start();
new Thread(out).start();
new Thread(out).start();
}
}


七、wait()、notify()、notifyAll()

作用:都是使用在同步中,因为要对持有监视器(锁)的线程操作

为什么这些操作线程的方法一定要定义在Object类中呢?

原因:因为这些方法在操作同步中的线程时,都必须标识他们所操作线程持有的锁,只有同一个锁上的被等待的线程可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒,以为不是同一把锁,也就是说:等待和唤醒必须是同一把锁,而锁可以是任意对象,所以可以被任意对象调用的方法要定义在Object类中

八、JDK1.5版本中提供的多线程升级方案

1.5版本新特性:

1、将同步synchronized替换成了显式Lock操作

2、将Object类中的wait、notify、notifyAll替换成了condition对象,该对象可以对lock锁进行获取

3、可以实现只唤醒对方的操作

结论:1.5版本之后提供了显式的锁机制,以及显式的锁对象上的等待唤醒操作机制,同时,它把等待唤醒机制进行了封装,封装完一个锁可以对应多个等待和唤醒

使用多线程升级方案演示线程间通信:

/*
需求:使用JDK1.5版本提供的多线程解决方法优化该项目
*/
//定义资源类
import java.util.concurrent.locks.*;
class Res
{
//定义成员变量用于作为共享数据被线程进行添加和输出
private String name;
private String sex;
//用于让线程等待
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
//定义输入线程要操作的代码,由于数据是成对(name,set)添加的,所以应同步
//public synchronized void setInput(String name, String sex){
public void setInput(String name,String sex)throws Exception//condition_pro.wait();会有异常,在这里我们抛出
{
//因为需要同步,所以应使用同步,1.5版本后使用Lock类中提供的lock方法开启锁
lock.lock();
//这里需要改变,因为是多个线程在操作同一段代码,唤醒后都需要判断
try{
while(flag)
//wait();//t1(放弃)(获取) t2(放弃)(获取)
//等待被替换为
condition_pro.wait();
this.name = name;
this.sex = sex;
System.out.println(Thread.currentThread().getName()+"...."+name+"...."+sex+".........................新添");
flag = true;
//notifyAll();//唤醒线程池中的所有线程,防止线程全部等待
//notifyAll()唤醒被替换为 可以只用来唤醒对方线程
condition_con.signal();
}
finally{
//关闭锁 必须放在finally语句快中
lock.unlock();
}
}
//定义输出线程要操作的代码,因为要使用同步,所以必须保证至少有两把锁,所以该函数也需要同步
//public synchronized void getOutput(){
//可以不用再函数上上锁
public void getOutput()throws Exception//condition_con.wait();会有异常,在这里我们抛出
{
lock.lock();
try{
while(!flag)
//wait();//t3(放弃)(获取) t4(放弃)(获取)
//wait()被替换为:
condition_con.wait();
System.out.println(Thread.currentThread().getName()+"........."+name+"...."+sex+"++++++++++++++++打印");
flag = false;
//notifyAll();
//notifyAll被替换为:
condition_pro.signal();
}
finally{
lock.unlock();
}

}

}
//定义输入线程
class Input implements Runnable
{
private int x;
private Res r;
Input(Res r){
this.r = r;
}
public void run(){
while(true){
try
{
r.setInput("MK","Man");
}
catch (Exception e)
{
}
}
}
}
//定义输出(打印)线程
class Output implements Runnable
{
private Res r;
Output(Res r){
this.r = r;
}
public void run(){
while(true){
try
{
r.getOutput();
}
catch (Exception e)
{
}
}
}
}
class ThreadDemo11
{
public static void main(String [] args){
Res r = new Res();
//创建输入对象,并作为实际参数传递,保证线程使用的是同一个对象
Input in = new Input(r);
Output out = new Output(r);
new Thread(in).start();
new Thread(in).start();
new Thread(out).start();
new Thread(out).start();
}
}

九、停止线程

停止线程的方式:

1、开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。

2、当遇到特殊情况时,比如线程处于了冻结状态,则第一种方式是没有办法结束线程的,当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。实现方式:Thread类提供的interrupt();方法 

class StopThread implements Runnable
{
private boolean flag =true;
public void run()
{
while(flag)
{

System.out.println(Thread.currentThread().getName()+"....run");
}
}
public void changeFlag()
{
flag = false;
}
}




class ThreadDemo12
{
public static void main(String[] args)
{
StopThread st = new StopThread();

Thread t1 = new Thread(st);
Thread t2 = new Thread(st);


t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();

int num = 0;
//用主线程控制t1、t2线程结束
while(true)
{
//当满足该条件时,让t1、t2线程结束
if(num++ == 60)
{
st.changeFlag();//利用控制线程循环条件,结束循环
t1.interrupt();//如果线程处于冻结状态,强制让线程回到运行状态,因为在冻结状态下无法操作标记,没办法操作标记,那么线程就停不下来
t2.interrupt();
System.out.println(Thread.currentThread().getName()+"......."+num);
break;//用于结束主线程
}
System.out.println("......."+num);
try{Thread.sleep(10);}catch(Exception e){}
}
}
}
十、线程类的其他方法

1、setDaemon(boolean boo)           返回值类型为 void

主要将该线程标记为守护线程或用户线程。

理解:守护线程可以理解为后台线程,而我们看到的线程其实都是前台线程,当你把某些线程表姐为后台线程后,他就具备了一个特殊的含义,后台线程的特点:开启后会和前台线程共同抢夺cpu的执行权运行,开启运行都没有区别,就结束有区别,当uoyou的前台线程都结束后,后台线程会自动结束,后台线程依赖于前台线程

2、join()          返回值类型void

主要用于等待线程终止 

理解:当主线程执行到join方法时,凡是在该方法后面的线程都会被处于冻结状态,只用当join线程结束后,后面的线程才会被执行

3、setPriority(int newPriority)   返回值类型为void

主要用于修改线程的优先级

线程优先级等级:     1级——10级   默认为5级

各个等级在Java中已经定义好了最终静态常量保存了1级、5级和10级   如图:

注:在给线程设置优先级时,只需要使用Thread类调用即可  如: setPriority(Thread.MAX_PKIORITY)    //设置最高优先级

4、yieId()    static  void

用于暂停当前正在执行的线程对象,并执行其他线程,就好比说我执行完了,该你了(就是你执行完听一次当抢夺到执行权后在执行,在等待...................)

线程终于写完了!!  完美!!!









































注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



Java基础(九)——多线程 Java多线程基础 Java多线程基础 Java基础:多线程 java基础-多线程 Java多线程基础 Java多线程基础 Java多线程-基础 java多线程基础 java 多线程基础
 
粤ICP备14056181号  © 2014-2020 ITdaan.com