黑马程序员_多线程(上)

-------- android培训java培训、期待与您交流!--------
/*
进程:是一个正在执行的程序
      每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或叫一个控制单元
线程:就是进程中的一个独立的控制单元
      线程在控制进程的执行,一个或多个线程在进程中运行,是最小单位

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

java VM 启动的时候有一个进程为java.exe
负责执行java程序的线程,为主线程

扩展:jvm启动不止一个线程,还有负责垃圾回收机制的线程

	
-----------

如何在自定义的代码中,定义一个线程

创建线程的第一种方式:继承Thread类
1.定义类继承Thread
2.复习Thread类中的run方法
    目的:将自定义代码存储在run方法中,让线程运行
3.调用线程的start方法,该方法的两个作用:启动线程,调用run方法	


static Thread currentThread():获取当前线程对象
getName():获取线程名称
设置线程名称:setName或者构造函数


*/
//创建两个线程,和主线程交替运行
class Test extends Thread//继承Thread
{
	//private String name;
	Test(String name)//设置线程的名称
	{
		//this.name = name;
		super(name);//可以直接调用父类方法
	}
	public void run()//覆盖run方法
	{
		for(int i=0;i<60;i++)
		{
			//Thread.currentThread()获取线程的对象 getName()获取该线程的名称
			System.out.println(Thread.currentThread().getName()+"....run..."+i);
			//System.out.println(name+"...@run...."+i);
		}
	}
}

class ThreadDemo
{
	public static void main(String[] args) 
	{
		Test t1 = new Test("one");
		Test t2 = new Test("two");

		t1.start();//开启线程并执行run方法
		t2.start();
		//t1.run();//不写start,就相当于调用run方法,线程没开启,t1.run()没执行完不会执行t2.run()
		//t2.run();

		for(int i=0;i<60;i++)
		{
			System.out.println("hello..."+i);
		}
	}
}


/*
需求:简单的卖票程序
多个窗口同时买票


创建线程的第二种方式:实现Runnable接口

步骤
1.定义类实现Runnable接口
     
2.覆盖Runnable接口中的run方法
	将线程要运行的代码放在该run方法中
3.通过Thread类建立线程对象
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
    为什么要将Runnable接口的子类对象传递给Thread类的构造函数?
	    因为,自定义的run方法所属的对象是Runnable接口的子类对象
		所以要让线程去指定特定对象的run方法,就必须明确该run方法所属的对象
5.调用Thread类的start方法开启线程并调用Runnable接口子类中的run方法

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

实现方式好处:避免了单继承的局限性
在定义线程时,建立使用实现方式

两种方式的区别:
继承Thread:线程代码存放Thread子类run方法中
实现Runnable,线程代码存在接口的子类的run方法

*/

class Ticket implements Runnable
{
	private int tick = 100;
	public void run()
	{
		while(true)
		{
			if(tick>0)
				System.out.println(Thread.currentThread().getName()+"..."+tick--);
		}
	}
}

class ThreadDemo2
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);
		t1.start();
		t2.start();
		t3.start();

	}
}




/*
 多线程的运行出现了安全问题

 问题的原因:
     当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,
	 还没有执行完,另外一个线程参与进来执行,导致共享数据错误
 解决办法:
    对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行

java对于多线程的安全问题了解决方式

同步代码块
synchronize(对象)
{
	需要被同步的代码
}

对象就像锁,持有锁的线程可以在同步中执行
没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁

同步的前提:
1.必须要有两个或者两个以上的线程
2.必须是多个线程使用同一个锁
 必须保证同步中只有一个线程在运行

 好处:解决了多线程的安全问题
 缺点:多个线程需要判断锁,较为消耗资源


*/
class Ticket implements Runnable
{
	private int tick = 100;
	Object obj = new Object();
	public void run()
	{
		while(true)
		{
			synchronized(obj)//同步代码块,不加上就会出现票号为负数的情况
			{		
				if(tick>0)
				{
					try{Thread.sleep(10);}catch(Exception e){}
					System.out.println(Thread.currentThread().getName()+"..."+tick--);
				}
			}
		}
	}
}

class ThreadDemo3
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);
		t1.start();
		t2.start();
		t3.start();

	}
}

/*
需求:
银行有一个金库
有两个储户分别存300元,每次存100,存3次

目的:该程序是否有安全问题,如果有,如果解决

如何找问题

1.明确哪些代码是是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中,哪些语句是操作共享数据的


*/
class Bank
{
	private int sum;//共享数据
	Object obj = new Object();
	public void add(int n)//多线程运行代码
	{
		synchronized(obj)
		{
			sum = sum + n;//操作共享数据的
			try
			{
				Thread.sleep(10);	
			}
			catch (Exception e)
			{
			}
			System.out.println("sum="+sum);//操作共享数据的
		}
	}
}

class Cus implements Runnable
{
	private Bank b = new Bank();//共享数据
	public void run()//多线程运行代码
	{
		for(int x = 0; x < 3; x++)//这里不用加同步,如果加了那么就只能让这个线程运行玩三次循环,就能轮到下一个线程了
		{
			b.add(100);//操作共享数据的
		}
	}
}


class ThreadDemo4 
{
	public static void main(String[] args) 
	{
		Cus c = new Cus();
		Thread t1 = new Thread(c);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
	}
}


-------- android培训java培训、期待与您交流!--------
黑马程序员多线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值