java基础------多线程
并行与并发的区别
并行:多个线程同时进行,要依赖多个cpu实现,
并发:cpu在线程之间切换,宏观上实现并行
1.线程的创建(2种方式)
(1)继承Thread类
(2)实现Runnable接口
package thread;
public class ThreadCreate {
/**
*
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread myThread = new MyThread();
Thread thread = new Thread(new MyRunnable());
//开启线程
myThread.start();
thread.start();
}
}
class MyThread extends Thread{
public void run(){
for(int i=0;i<100;++i){
System.out.println(Thread.currentThread().getName()+":hahaha!");
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<100;++i){
System.out.println(Thread.currentThread().getName()+":heiheihei!");
}
}
}
2.同步代码块(synchronized)
作用:当我们希望cpu在执行一段代码时,不切换到其他线程
package thread;
public class ThreadCreate {
/**
*
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread myThread = new MyThread();
Thread thread = new Thread(new MyRunnable());
myThread.start(); //开启线程
thread.start();
}
}
class MyThread extends Thread{
public void run(){
synchronized (ThreadCreate.class) { //使用ThreadCreate.class对象做monitor
for(int i=0;i<100;++i){
System.out.println(Thread.currentThread().getName()+":hahaha!");
}
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
synchronized (ThreadCreate.class) {
for(int i=0;i<100;++i){
System.out.println(Thread.currentThread().getName()+":heiheihei!");
}
}
}
}
2.同步方法
(1)静态同步方法的锁对象时字节码对象 类名.class
(2)非静态同步方法的锁对象是调用该方法的类对象
3.集合线程安全问题
(1)Vector(安全) ArrayList
(2)StringBuffer(安全) StringBuilder
(3)HashTable(安全) HashMap
ps:线程不安全的集合可以转为安全的集合,例如:
List<String> list =Collections.synchronizedList(new ArrayList<String>());
当然,也可以去重写这些集合的动态方法,以实现线程安全
根据同步的特性模拟多个售票点售票
package thread;
public class TicketsSell {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread thread1 = new Thread(new TicketsSeller());
Thread thread2 = new Thread(new TicketsSeller());
Thread thread3 = new Thread(new TicketsSeller());
Thread thread4 = new Thread(new TicketsSeller());
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
class TicketsSeller implements Runnable{
private static int tickets = 10000;
@Override
public void run() {
// TODO Auto-generated method stub
while(tickets>0){
//if(tickets>0){
synchronized (TicketsSeller.class) {
if(tickets>0){
System.out.println(Thread.currentThread().getName()+":第"+tickets+"号票已售出!");
tickets--;
}
}
}
}
}
3.线程间的通信
需求:一个线程打印[1,100]的奇数,一个线程打印[1,100]的偶数。
package thread;
public class ThreadTurning {
private static int nums = 100;
/**
*
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final String s = new String();
new Thread(){ //匿名内部类继承Thread类
public void run(){
synchronized (s) { //匿名内部类使用局部变量必须将其声明为final
while(nums>0){
if(nums%2==1){
System.out.println(Thread.currentThread().getName()+":"+nums--+"!!!");
}
s.notifyAll();
try {
s.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (s) {
while(nums>0){
if(nums%2==0){
System.out.println(Thread.currentThread().getName()+":"+nums--+"!!!");
}
s.notifyAll();
try {
s.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
s.notifyAll(); //这个很重要,否则上面那个线程将一直处在wait...
}
}
}).start();
}
}