多线程-同步的两种方式
一个储户,向两个账户存钱,每次存100,共存3次
public class Demo { public static void main(String[] args) { Cus c = new Cus();//只为多个【线程】创建一个【线程任务】对象,否则同步是没有意义的 new Thread(c, "第一个线程").start(); new Thread(c, "第二个线程").start(); } }
class Bank {//银行账户 private int sum;//账户1金额 private int sum2;//账户2金额 public synchronized void add(int num) {//同步函数,锁为this。若方法中有很多代码不需要同步,则使用同步函数会降低效率。 sum = sum + num; try { Thread.sleep(10); } catch (InterruptedException e) { } System.out.println("账户1金额=" + sum); } public void add2(int num) { synchronized (this) {//同步代码块,锁可以为任意对象。因为可以使用同步代码块仅将需要同步的部分上锁,所以锁的范围比同步函数小,所以效率相对要高 sum2 = sum2 + num; System.out.println(" 账户2金额=" + sum2); } } }
//储户类,需多线程处理的行为是:向账户中存钱 class Cus implements Runnable { private Bank b = new Bank();//银行账户 public void run() { for (int x = 0; x < 3; x++) { b.add(100);//向账户1存钱 b.add2(100);//向账户2存钱 } } }
账户1金额=100 账户1金额=200 账户2金额=100 账户1金额=300 账户2金额=200 账户1金额=400 账户2金额=300 账户2金额=400 账户1金额=500 账户2金额=500 账户1金额=600 账户2金额=600
多线程-死锁-互锁
public class Demo { public static void main(String[] args) { System.out.println("开始"); new Thread(new Test1(true)).start(); new Thread(new Test1(false)).start(); } }
class Test1 implements Runnable { static private int num = 1;//设置为静态可以用来标记总执行次数 private boolean flag; Test1(boolean flag) {//通过改变对象的状态值,来触发对象不同的代码块 this.flag = flag; } static Object locka = new Object(); static Object lockb = new Object(); //为什么这两货一定要用静态修饰?因为,若是非静态的,则后面创建的两个Test1对象的此属性不是同一个对象,那么就无法同步,也不会有死锁发生 public void run() { if (flag) { while (true) synchronized_logic1(); } else { while (true) synchronized_logic2(); } }
private void synchronized_logic1() { synchronized (locka) {//先获得【a】锁 System.out.println(Thread.currentThread().getName() + "..if a....执行次数" + num++); synchronized (lockb) {//再获得【b】锁(嵌套) System.out.println(Thread.currentThread().getName() + "..if b....执行次数" + num++); } try { Thread.sleep(1);//目的是让子弹飞一会 } catch (InterruptedException e) { } } } private void synchronized_logic2() { synchronized (lockb) {//先获得【b】锁 System.out.println(Thread.currentThread().getName() + "..else b....执行次数" + num++); synchronized (locka) {//再获得【a】锁(嵌套) System.out.println(Thread.currentThread().getName() + "..else a....执行次数" + num++); } try { Thread.sleep(1);//目的是让子弹飞一会 } catch (InterruptedException e) { } } } }
多线程-死锁-嵌套
public class Demo { public static void main(String[] args) { Ticket2 t = new Ticket2(); Thread t1 = new Thread(t); Thread t2 = new Thread(t);//这两个线程是同步的 t1.start();//线程1启动,且启动后不会关闭 try { Thread.sleep(100);//让子弹飞一会 t.flag = false;//将状态改变,以便能启动线程2 } catch (InterruptedException e) { e.printStackTrace(); } t2.start();//线程2启动,且启动后不会关闭 System.out.println("main线程已经执行完了--------------------"); } }
class Ticket2 implements Runnable { private int num; private Object obj = new Object(); public boolean flag = true;//设置一个状态,以便能通过改变这个状态来触发方法 public void run() { if (flag) { while (true) { synchronized (obj) {//请求获得obj锁 show();//请求获得this锁 } } } else { while (true) { show(); } } } public synchronized void show() { synchronized (obj) {//请求获得obj锁 System.out.println("当停止输出时,说明死锁发生了--" + num++ + "--" + flag); } } }
Thread 线程类API
构造方法
- Thread() 分配新的 Thread 对象
- Thread(Runnable target) 分配新的 Thread 对象
- Thread(Runnable target, String name) 分配新的 Thread 对象
- Thread(String name) 分配新的 Thread 对象
- Thread(ThreadGroup group, Runnable target) 分配新的 Thread 对象
- Thread(ThreadGroup group, Runnable target, String name) 分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,并作为 group 所引用的线程组的一员
- Thread(ThreadGroup group, Runnable target, String name, long stackSize) 分配新的 Thread 对象,将target作为其运行对象,将name作为其名称,作为group所引用的线程组的一员,并具有指定的堆栈大小
- Thread(ThreadGroup group, String name) 分配新的 Thread 对象
变量&常量
- static int MAX_PRIORITY 线程可以具有的最高优先级。
- static int MIN_PRIORITY 线程可以具有的最低优先级。
- static int NORM_PRIORITY 分配给线程的默认优先级。
公共方法
- static int activeCount() 返回当前线程的线程组中活动线程的数目。
- void checkAccess() 判定当前运行的线程是否有权修改该线程。
- int countStackFrames() 已过时。
- static Thread currentThread() 返回对当前正在执行的线程对象的引用。
- void destroy() 已过时。
- static void dumpStack() 将当前线程的堆栈跟踪打印至标准错误流。
- static int enumerate(Thread[] tarray) 将当前线程的线程组及其子组中的活动线程复制到数组中。
- static Map getAllStackTraces() 返回所有活动线程的堆栈跟踪的一个映射。
- ClassLoader getContextClassLoader() 返回该线程的上下文 ClassLoader。
- static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() 返回线程由于未捕获到异常而突然终止时调用的默认处理程序。
- long getId() 返回该线程的标识符。
- String getName() 返回该线程的名称。
- int getPriority() 返回线程的优先级。
- StackTraceElement[] getStackTrace() 返回一个表示该线程堆栈转储的堆栈跟踪元素数组。
- Thread.State getState() 返回该线程的状态。
- ThreadGroup getThreadGroup() 返回该线程所属的线程组。
- Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() 返回该线程由于未捕获到异常而突然终止时调用的处理程序。
- static boolean holdsLock(Object obj) 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
- void interrupt() 中断线程。
- static boolean interrupted() 测试当前线程是否已经中断。
- boolean isAlive() 测试线程是否处于活动状态。
- boolean isDaemon() 测试该线程是否为守护线程。
- boolean isInterrupted() 测试线程是否已经中断。
- void join() 等待该线程终止。这名字好JB奇葩啊!
- void join(long millis) 等待该线程终止的时间最长为 millis 毫秒。
- void join(long millis, int nanos) 等待该线程终止的时间最长为 millis 毫秒+nanos 纳秒
- void resume() 已过时。
- void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
- void setContextClassLoader(ClassLoader cl) 设置该线程的上下文 ClassLoader。
- void setDaemon(boolean on) 将该线程标记为守护线程或用户线程,当正在运行的线程都是守护线程是,Java虚拟机退出。该方法必须在启动线程前使用。
- static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) 设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序
- void setName(String name) 改变线程名称,使之与参数 name 相同。
- void setPriority(int newPriority) 更改线程的优先级。
- void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) 设置该线程由于未捕获到异常而突然终止时调用的处理程序。
- static void sleep(long millis) 在指定的毫秒数内让【当前】正在执行的线程休眠
- static void sleep(long millis, int nanos) 在指定的毫秒数+纳秒数内让当前正在执行的线程休眠
- void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
- void stop() 已过时。
- void stop(Throwable obj) 已过时。
- void suspend() 已过时。
- String toString() 返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
- static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
时间: 2024-12-28 16:18:12